技术/前端/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,初始化一个promiseconst 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数字,表示正在执行的promiseexecuting.push(e);// 使用Promise.race,每当executing数组中promise数量低于poolLimit,就实例化新的promise并执行let r = Promise.resolve();if (executing.length >= poolLimit) {r = Promise.race(executing);}// 递归,直到遍历完arrayreturn 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特性和递归,完美实现了要求的功能,而且能很好地控制并发。
