技术/前端/ECMAScript

今天在一个技术群里,有人提了一个问题:如何实现一个方法,里面逻辑要求,一组请求,限制最大并发m个,所有请求结束后执行回调函数。

一开始就想到用Promise.all方法实现,对所有请求分组,每组m个请求,但是仔细一想,每组执行时其实已经发出了所有请求,而且,还要处理各组之间的等待问题,感觉没有想得那么容易,问google发现一个很赞的库,正是解决这种问题的,async-pool

  1. function asyncPool(poolLimit, array, iteratorFn) {
  2. let i = 0;
  3. const ret = [];
  4. const executing = [];
  5. const enqueue = function () {
  6. // 边界处理,array为空数组
  7. if (i === array.length) {
  8. return Promise.resolve();
  9. }
  10. // 每调一次enqueue,初始化一个promise
  11. const item = array[i++];
  12. const p = Promise.resolve().then(() => iteratorFn(item, array));
  13. // 放入promises数组
  14. ret.push(p);
  15. // promise执行完毕,从executing数组中删除
  16. const e = p.then(() => executing.splice(executing.indexOf(e), 1));
  17. // 插入executing数字,表示正在执行的promise
  18. executing.push(e);
  19. // 使用Promise.race,每当executing数组中promise数量低于poolLimit,就实例化新的promise并执行
  20. let r = Promise.resolve();
  21. if (executing.length >= poolLimit) {
  22. r = Promise.race(executing);
  23. }
  24. // 递归,直到遍历完array
  25. return r.then(() => enqueue());
  26. };
  27. return enqueue().then(() => Promise.all(ret));
  28. }

上面的代码大概逻辑:

  • 遍历请求组,初始化promise对象,存在ret数组中,同时创建excuting数组保存正在执行的promise,直到达到并发限制poolLimit
  • 使用Promise.race和一个空promise比较,获取正在执行executing中promise的执行情况,如有结束的promise,删除并初始化一个新的promise
  • 所有promise执行结束后调用Promise.all返回

思路真的很赞,利用promise特性和递归,完美实现了要求的功能,而且能很好地控制并发。