异步并发量控制

需求

设计一个方法,限制进入方法的异步函数数组的并发数。

分析

  1. 异步函数,使用返回Promise对象的函数实现;
  2. 调用数(limit)可配置;
  3. 可以通过Promise.race来实现有限并发和完成后更新并发列表的功能。

优化

  1. 使用Typescript实现,优化类型提示;
  2. 参照Promise.allSettled的Return风格,顺序返回异步函数结果集Promise对象;

实现

function promiseQueue<T extends readonly (() => Promise<any>)[] | []>(
  promiseList: T,
  limit = 5
): Promise<{
  -readonly [P in keyof T]: T[P] extends () => infer K
    ? PromiseSettledResult<Awaited<K>>
    : never;
}> {
  limit = Math.min(promiseList.length, limit);
  let pendingList: Promise<any>[] = [];
  const result: PromiseSettledResult<any>[] = [];
  // 装饰异步方法,实现待请求队列
  const _promiseList = promiseList.map((promiseFn, idx) => () => {
    const promise = promiseFn()
      .then(value => {
        result[idx] = {
          status: 'fulfilled',
          value
        };
      })
      .catch(reason => {
        result[idx] = {
          status: 'rejected',
          reason
        };
      })
      .finally(() => {
        pendingList = pendingList.filter(_promise => _promise !== promise);
      });
    return promise;
  });
  // 请求中队列
  pendingList = Array.from({ length: limit }, () => 0).map(() =>
    _promiseList.shift()!()
  );
  
  // 返回一个Promise
  return new Promise<any>(resolve => {
    // 递归
    const racer = () => {
      if (!_promiseList.length && !pendingList.length) {
        // 当待请求队列&请求中队列为空时,返回结果
        return resolve(result);
      }
      // 请求入列
      if (_promiseList.length) pendingList.push(_promiseList.shift()!());
      return Promise.race(pendingList).finally(() => {
        racer();
      });
    };
    racer();
  });
复制代码

Guess you like

Origin juejin.im/post/7074882531312533518