一、前言
在开发过程中,有时会遇到需要控制任务并发执行数量的需求。
例如一个爬虫程序,可以通过限制其并发任务数量来降低请求频率,从而避免由于请求过于频繁被封禁问题的发生。
接下来,本文介绍如何实现一个并发控制器。
二、示例
const task = timeout => new Promise((resolve) => setTimeout(() => {
resolve(timeout);
}, timeout))
const taskList = [1000, 3000, 200, 1300, 800, 2000];
async function startNoConcurrentControl() {
console.time(NO_CONCURRENT_CONTROL_LOG);
await Promise.all(taskList.map(item => task(item)));
console.timeEnd(NO_CONCURRENT_CONTROL_LOG);
}
startNoConcurrentControl();
上述示例代码利用 Promise.all 方法模拟6个任务并发执行的场景,执行完所有任务的总耗时为 3000 毫秒。
下面会采用该示例来验证实现方法的正确性。
三、实现
由于任务并发执行的数量是有限的,那么就需要一种数据结构来管理不断产生的任务。
队列的「先进先出」特性可以保证任务并发执行的顺序,在 JavaScript 中可以通过「数组来模拟队列」:
class Queue {
constructor() {
this._queue = [];
}
push(value) {
return this._queue.push(value);
}
shift() {
return this._queue.shift();
}
isEmpty() {
return this._queue.length === 0;
}
}
对于每一个任务,需要管理其执行函数和参数:
class DelayedTask {
constructor(resolve, fn, args) {