答案:并发控制是限制同时执行的异步任务数量,通过任务队列和运行计数实现。例如最多2个并发,后续任务需等待空位释放;Scheduler类维护queue和running状态,任务以函数形式传入避免提前执行,完成时触发下一个任务,确保系统稳定。

在处理大量异步任务时,直接并发执行所有 Promise 可能导致资源耗尽或接口限流。为此,需要一个Promise 调度器来控制并发数量,确保系统稳定运行。这类问题常见于批量请求、文件上传、爬虫抓取等场景。
什么是并发控制?
并发控制指的是限制同时执行的异步任务数量。例如,有 10 个请求,但最多只允许 3 个同时进行,其余任务排队等待空位释放。
JavaScript 是单线程语言,异步任务通过事件循环调度,而我们可以通过手动管理任务队列实现并发控制。
实现一个简单的调度器 Scheduler
目标:实现一个 Scheduler 类,支持添加异步任务,并限制最大并发数。
立即学习“Java免费学习笔记(深入)”;
示例需求:- 最多同时运行 2 个任务
- add(Promise) 方法用于添加任务
- 自动按顺序执行,空位释放后继续执行后续任务
代码实现:
class Scheduler {
constructor(maxConcurrent = 2) {
this.maxConcurrent = maxConcurrent;
this.running = 0;
this.queue = [];
}
add(promiseGenerator) {
return new Promise((resolve, reject) => {
const runTask = () => {
if (this.running < this.maxConcurrent && this.queue.length > 0) {
this.running++;
const { promise, resolve: res, reject: rej } = this.queue.shift();
promise()
.then(res)
.catch(rej)
.finally(() => {
this.running--;
runTask(); // 触发下一个
});
}
};
this.queue.push({
promise: promiseGenerator,
resolve,
reject
});
// 尝试启动任务
if (this.running < this.maxConcurrent) {
runTask();
}
});
}
}
使用方式:
const scheduler = new Scheduler(2); const timeout = (time) => () => new Promise(resolve => setTimeout(() => resolve(time), time)); scheduler.add(timeout(1000)).then(console.log); // 1s 后输出 1000 scheduler.add(timeout(500)).then(console.log); // 500ms 后输出 500 scheduler.add(timeout(300)).then(console.log); // 第三个要等前面有空位 scheduler.add(timeout(400)).then(console.log);
输出顺序:
500(第2个完成)
1000(第1个完成)
300(第3个开始并完成)
400(第4个开始并完成)
核心逻辑说明
调度器的关键在于:
- 维护一个任务队列 queue,存放未执行的任务
- 记录当前正在运行的任务数 running
- 每个任务完成后触发 runTask 尝试拉取新任务
- 任务以函数形式传入(返回 Promise),避免提前触发
注意:必须传入“返回 Promise 的函数”,否则任务在调用 add 时就已经开始执行,失去控制意义。
扩展思路
实际应用中可以进一步优化:
- 支持优先级队列,高优任务插队
- 提供取消任务的能力
- 暴露当前状态(running / waiting)供监控
- 结合 AbortController 实现超时中断
基本上就这些。一个轻量的调度器不需要复杂设计,关键是理解“任务入队 + 执行反馈触发下一轮”的闭环机制。










