devStandard/docs/learning/3-js/4-promise-all限制并发.md
2025-03-29 14:35:49 +08:00

2.5 KiB
Raw Permalink Blame History

promise all 并发限制

async-pooles6-promise-poolp-limit

async-pool的代码:

function asyncPool(poolLimit, array, iteratorFn) {
    let i = 0;
    const ret = [];
    const executing = [];
    const enqueue = function () {
        // 边界处理array为空数组
        if (i === array.length) {
            return Promise.resolve();
        }
        // 每调一次enqueue初始化一个promise
        const item = array[i++];
        const p = Promise.resolve().then(() => iteratorFn(item, array));
        // 放入promises数组
        ret.push(p);
        // promise执行完毕从executing数组中删除
        const e = p.then(() => executing.splice(executing.indexOf(e), 1));
        // 插入executing数字表示正在执行的promise
        executing.push(e);
        // 使用Promise.rece每当executing数组中promise数量低于poolLimit就实例化新的promise并执行
        let r = Promise.resolve();
        if (executing.length >= poolLimit) {
            r = Promise.race(executing);
        }
        // 递归直到遍历完array
        return r.then(() => enqueue());
    };
    return enqueue().then(() => Promise.all(ret));
}

因为是promise加上递归所以在代码注释上不太好标注执行顺序但是大概的逻辑可以总结为

  1. array第1个元素开始初始化promise对象,同时用一个executing数组保存正在执行的promise
  2. 不断初始化promise直到达到poolLimt
  3. 使用Promise.race,获得executing中promise的执行情况当有一个promise执行完毕继续初始化promise并放入executing
  4. 所有promise都执行完了调用Promise.all返回

使用方式就是:

const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i));
return asyncPool(2, [1000, 5000, 3000, 2000], timeout).then(results => {
    ...
});
  • Promise.all(iterable) 方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都"完成resolved"或参数中不包含 promise 时回调完成resolve如果参数中 promise 有一个失败rejected此实例回调失败reject失败原因的是第一个失败 promise 的结果