🤖

Promise.all()の並列実行数を制限する関数

に公開
function createParallelExecutor(throttle: number) {
  let _index = 0;
  const processingSet: Set<number> = new Set();

  return function executeWithLimit<T>(callback: () => Promise<T>): Promise<T> {
    const index = _index++;

    return new Promise((resolve, reject) => {
      const timer = setInterval(() => {
        if (processingSet.size >= throttle) return;
        if (processingSet.has(index)) return;

        processingSet.add(index);
        clearInterval(timer);

        callback()
          .then((response: T) => {
            processingSet.delete(index);
            resolve(response);
          })
          .catch((err) => {
            processingSet.delete(index);
            reject(err);
          });
      }, 100);
    });
  };
}

使い方

function sleep(id: number, time: number): Promise<number> {
  return new Promise((resolve) => {
    setTimeout(() => resolve(id), time)
  })
}

const executeWithLimit = createParallelExecutor(3)
const promises = []
for (let i = 1; i <= 9; i++) {
  promises.push(executeWithLimit(async () => {
    console.log(`start ${i}`)
    const result = await sleep(i, 3000)
    console.log(`end   ${i}`)
    return result
  }))
}

Promise.all(promises)
  .then(result => console.log({result}))

結果

start 1
start 2
start 3
end   1
end   2
end   3
start 4
start 5
start 6
end   4
end   5
end   6
start 7
start 8
start 9
end   7
end   8
end   9
{
  result: [
    1, 2, 3, 4, 5,
    6, 7, 8, 9
  ]
}

はい

Discussion