应用场景

  • 使用无头浏览器批量对一组网址截屏、生成 PDF
  • 请求 10 个 API 接口,按顺序执行,指定并发数量,比如每组最多 3 个同时执行
  • 一组异步任务,依次执行,每次只能执行一个
  • … 其它异步场景

具体实现

  1. /**
  2. * @description 创建一个异步队列
  3. * @param {Array} tasks 待执行异步任务队列
  4. * @param {Number} maxNumOfWorkers 最大并行任务数
  5. * @returns {Array} 队列中每个异步任务的执行结果
  6. */
  7. function createQueue(tasks, maxNumOfWorkers = 3) {
  8. let numOfWorkers = 0;
  9. let taskIndex = 0;
  10. return new Promise(done => {
  11. const handleResult = index => result => {
  12. tasks[index] = result;
  13. numOfWorkers--;
  14. getNextTask();
  15. };
  16. function getNextTask() {
  17. if (numOfWorkers < maxNumOfWorkers && taskIndex < tasks.length) {
  18. tasks[taskIndex]()
  19. .then(handleResult(taskIndex))
  20. .catch(handleResult(taskIndex));
  21. taskIndex++;
  22. numOfWorkers++;
  23. getNextTask();
  24. } else if (numOfWorkers === 0 && taskIndex === tasks.length) {
  25. done(tasks);
  26. }
  27. }
  28. getNextTask();
  29. });
  30. }

举例演示

play-codesandbox.svg

  1. // 模拟异步任务
  2. const getAPI = waitTime => () => {
  3. if (waitTime === 800) return Promise.reject(new Error("sorry"));
  4. return new Promise(resolve =>
  5. setTimeout(() => {
  6. console.log("> async task GET /api wait %d.", waitTime);
  7. resolve(waitTime);
  8. }, waitTime)
  9. );
  10. };
  11. // 创建异步队列并执行,返回所有异步任务的执行结果
  12. createQueue([
  13. getAPI(3000),
  14. getAPI(4000),
  15. getAPI(3000),
  16. getAPI(3000),
  17. getAPI(800),
  18. getAPI(2000),
  19. getAPI(3000),
  20. getAPI(2200),
  21. getAPI(1240)
  22. ]).then(result => console.log(result));

输出结果:

  1. > async task GET /api wait 3000.
  2. > async task GET /api wait 3000.
  3. > async task GET /api wait 4000.
  4. > async task GET /api wait 2000.
  5. > async task GET /api wait 3000.
  6. > async task GET /api wait 3000.
  7. > async task GET /api wait 2200.
  8. > async task GET /api wait 1240.
  9. [3000, 4000, 3000, 3000, Error, 2000, 3000, 2200, 1240]