技术/前端/ECMAScript
今天在一个技术群里,有人提了一个问题:如何实现一个方法,里面逻辑要求,一组请求,限制最大并发m个,所有请求结束后执行回调函数。
一开始就想到用Promise.all
方法实现,对所有请求分组,每组m个请求,但是仔细一想,每组执行时其实已经发出了所有请求,而且,还要处理各组之间的等待问题,感觉没有想得那么容易,问google发现一个很赞的库,正是解决这种问题的,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.race,每当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对象,存在ret数组中,同时创建excuting数组保存正在执行的promise,直到达到并发限制poolLimit
- 使用
Promise.race
和一个空promise比较,获取正在执行executing中promise的执行情况,如有结束的promise,删除并初始化一个新的promise - 所有promise执行结束后调用
Promise.all
返回
思路真的很赞,利用promise特性和递归,完美实现了要求的功能,而且能很好地控制并发。