考点: promise的应用能力
Promise 异步流程控制

预备

promise中race、all、allSettled 区别

  • Promise.race(iterable) 某个解决/拒绝
  • Promise.all(iterable) 有一个被拒绝就抛出异常, 否则全部结束后以数组形式返回
  • Promise.allSettled(iterable) 全部结束后, 以数组形式返回结果
  • Promise.any(iterable) 有一个成功及返回成功, 全部失败抛出异常 (暂未被浏览器完全支持)

    请求池[快手]

    image.png

实现可控制并发请求数的请求方法

实现可控制并发请求数的请求方法,并且最大化利用空闲通道

  1. // 实现可控制并发请求数的请求方法,并且最大化利用空闲通道
  2. // 提供fetch函数做网络请求,可以这样调用

实现一个批量请求函数 multiRequest(urls, maxNum),要求如下:

• 要求最大并发数 maxNum
• 每当有一个请求返回,就留下一个空位,可以增加新的请求
• 所有请求完成后,结果按照 urls 里面的顺序依次打出复制代码

参考答案:

  1. function multiRequest(urls = [], maxNum) { // 请求总数量
  2. const len = urls.length; // 根据请求数量创建一个数组来保存请求的结果
  3. const result = new Array(len).fill(false); // 当前完成的数量
  4. let count = 0;
  5. return new Promise((resolve, reject) => {// 请求maxNum个
  6. while (count < maxNum) {
  7. next();
  8. }
  9. function next() {
  10. let current = count++; // 处理边界条件
  11. if (current >= len) {
  12. // 请求全部完成就将promise置为成功状态, 然后将result作为promise值返回
  13. !result.includes(false) && resolve(result);
  14. return;
  15. }
  16. const url = urls[current];
  17. console.log(`开始 ${current}`, new Date().toLocaleString());
  18. fetch(url)
  19. .then((res) => {
  20. // 保存请求结果
  21. result[current] = res;
  22. console.log(`完成 ${current}`, new Date().toLocaleString());
  23. // 请求没有全部完成, 就递归 if (current < len) {
  24. next();
  25. }
  26. })
  27. .catch((err) => {
  28. console.log(`结束 ${current}`, new Date().toLocaleString());
  29. result[current] = err;
  30. // 请求没有全部完成, 就递归
  31. if (current < len) {
  32. next();
  33. }
  34. });
  35. }
  36. });
  37. }

相似描述:
实现一个n个请求并发的sendRequest(urls, max, callback)函数
请实现下的函数,可以批量请求数据,所有的url地址在urls参数中,同时可以
通过max参数控制请求的并发度,当所有请求结束之后,需要执行callback回调函数,
发请求的函数可以直接使用fetch即可

异步调度器schedule[字节]

js实现一个带并发限制的异步调度器schedule,保证同时运行的任务最多有两个。

完善下边代码中的Scheduler 类, 是的以下程序正确输出。

  1. class Scheduler {
  2. add(promiseCreator) {
  3. // TODO
  4. }
  5. }
  6. const timeout = (time) => new Promise(resolve => {
  7. setTimeout(resolve, time)
  8. })
  9. const scheduler = new Scheduler()
  10. const addTask = (time, order) => {
  11. scheduler.add(() => timeout(time)).then(() => console.log(order))
  12. }
  13. addTask(1000, '1');
  14. addTask(500, '2');
  15. addTask(300, '3');
  16. addTask(400, '4');
  17. // output: 2 3 1 4
  18. // 一开始, 1, 2两个任务进入队列
  19. // 500ms时, 2完成, 输出2, 任务3进队
  20. // 800ms时, 3完成, 输出3, 任务4进队
  21. // 1000ms时, 1完成, 输出1
  1. Promise.race

    1. class Scheduler {
    2. constructor (maxCount) {
    3. this.maxCount = maxCount || 2;
    4. this.taskList = [];
    5. this.process = [];
    6. }
    7. add(promiseCreator) {
    8. this.taskList.unshift(promiseCreator)
    9. return this.start();
    10. }
    11. start () {
    12. if (this.process.length < this.maxCount && this.taskList.length > 0) {
    13. let task = this.taskList.pop();
    14. let promise = task().then(() => {
    15. let index = this.process.indexOf(promise);
    16. this.process.splice(index, 1);
    17. });
    18. this.process.push(promise);
    19. return promise;
    20. } else {
    21. return Promise.race(this.process).then(() => this.start());
    22. }
    23. }
    24. }

    参考:
    https://www.mdeditor.tw/pl/2MGN