应用场景
- 使用无头浏览器批量对一组网址截屏、生成 PDF
- 请求 10 个 API 接口,按顺序执行,指定并发数量,比如每组最多 3 个同时执行
- 一组异步任务,依次执行,每次只能执行一个
- … 其它异步场景
具体实现
/**
* @description 创建一个异步队列
* @param {Array} tasks 待执行异步任务队列
* @param {Number} maxNumOfWorkers 最大并行任务数
* @returns {Array} 队列中每个异步任务的执行结果
*/
function createQueue(tasks, maxNumOfWorkers = 3) {
let numOfWorkers = 0;
let taskIndex = 0;
return new Promise(done => {
const handleResult = index => result => {
tasks[index] = result;
numOfWorkers--;
getNextTask();
};
function getNextTask() {
if (numOfWorkers < maxNumOfWorkers && taskIndex < tasks.length) {
tasks[taskIndex]()
.then(handleResult(taskIndex))
.catch(handleResult(taskIndex));
taskIndex++;
numOfWorkers++;
getNextTask();
} else if (numOfWorkers === 0 && taskIndex === tasks.length) {
done(tasks);
}
}
getNextTask();
});
}
举例演示
// 模拟异步任务
const getAPI = waitTime => () => {
if (waitTime === 800) return Promise.reject(new Error("sorry"));
return new Promise(resolve =>
setTimeout(() => {
console.log("> async task GET /api wait %d.", waitTime);
resolve(waitTime);
}, waitTime)
);
};
// 创建异步队列并执行,返回所有异步任务的执行结果
createQueue([
getAPI(3000),
getAPI(4000),
getAPI(3000),
getAPI(3000),
getAPI(800),
getAPI(2000),
getAPI(3000),
getAPI(2200),
getAPI(1240)
]).then(result => console.log(result));
输出结果:
> async task GET /api wait 3000.
> async task GET /api wait 3000.
> async task GET /api wait 4000.
> async task GET /api wait 2000.
> async task GET /api wait 3000.
> async task GET /api wait 3000.
> async task GET /api wait 2200.
> async task GET /api wait 1240.
[3000, 4000, 3000, 3000, Error, 2000, 3000, 2200, 1240]