控制Promise并发量

93 阅读1分钟
  1. 主要思想就是建立一个中间人channel,一边写入,一边删除,需要理解阻塞和放行,在循环中使用await阻塞向channel中写入数据。
  2. 为什么必须使用Promise.race(pool) 而不是Promise.all(pool) ?
  • Promise.all要等待所有的promise变为成功状态。假设pool中有10个promise,其中一个非常耗时1min,其他9个只需要1s,使用Promise.all需要等待1min,await才会放行,循环才会继续,白白等待59s。

  • 使用Promise.race可以保证,pool中最快的promise改变状态时,await就会放行,继续向pool写入新的promise,通俗来讲,就是1个promise运行结束的同时1个新的promise加入,没有时间间隔

const response = async (id) => {... }
const summarys = new Map();
const retry = new Set();
const asyncRun = async (ids, summarys) => {
    const limit = 3;
    // limit个异步任务
    const pool = new Set();
    const retry = new Set();

    for (const id of ids){
         const task = response(id); //一个请求网页的函数
         pool.add(task); // 保存新的异步任务

         task.then((s) => {
              summarys.set(id, s);
         }).catch((err) => {
              retry.add(id);
         }).finally(() => {
              pool.delete(task);
          });
         if (pool.size < limit) {
              continue;
         }

         try {
              await Promise.race(pool);
              //阻塞主循环,直到pool中最快的一个promise状态改变
         } catch {
              continue;
         }

    }
    await Promise.allSettled(pool);
    //等待pool余下的promise状态改变,无论状态是否成功

    if (retry.size) {
         asyncRun(retry, summarys);
    } else {
         console.log("执行结束");
    }
};

asyncRun(ids, summarys);

支持promise在rejected后重新进入任务列表