Promise并发任务队列通过维护running计数器和tasks队列实现,每次最多执行n个任务,完成一个即调度下一个;核心是schedule递归调度、微任务保障及时性、错误隔离不中断队列。

用 Promise 实现并发控制的任务队列,核心是维护一个“运行中任务数”和一个“待执行任务队列”,每次只允许最多 n 个任务同时执行,前一个完成再启动下一个等待任务。
基本思路:用数组 + 计数器 + 递归调度
不依赖外部库,纯 JS 即可实现。关键点有三个:
- 用一个数组缓存待执行的异步任务(每个任务是返回 Promise 的函数)
- 用一个计数器
running跟踪当前正在执行的任务数量 - 定义一个
schedule()函数,它检查是否还能启动新任务;能就取一个出来执行,并在.then()或.catch()后再次调用自己
简单可复用的实现示例
下面是一个轻量、无依赖的并发队列类:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
class TaskQueue {
constructor(concurrency = 1) {
this.concurrency = concurrency;
this.tasks = [];
this.running = 0;
}
push(taskFn) {
return new Promise((resolve, reject) => {
this.tasks.push({ taskFn, resolve, reject });
this.schedule();
});
}
schedule() {
while (this.running < this.concurrency && this.tasks.length > 0) {
const { taskFn, resolve, reject } = this.tasks.shift();
this.running++;
Promise.resolve().then(() => taskFn())
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
})
.finally(() => {
this.running--;
this.schedule(); // 尝试调度下一个
});
}
}
}
// 使用示例:限制最多 2 个请求同时发出去
const queue = new TaskQueue(2);
const fetchWithDelay = (url, delay = 1000) =>
() => new Promise(r => setTimeout(() => r(`done: ${url}`), delay));
queue.push(fetchWithDelay('/api/a'));
queue.push(fetchWithDelay('/api/b'));
queue.push(fetchWithDelay('/api/c'));
queue.push(fetchWithDelay('/api/d'));
// a、b 几乎同时开始;c 在 a 或 b 完成后启动;d 类推
注意点和常见优化
实际使用时要注意几个细节:
立即学习“Java免费学习笔记(深入)”;
-
避免同步任务阻塞调度:用
Promise.resolve().then(...)把任务推到微任务队列,保证调度逻辑不被同步代码卡住 -
错误不中断队列:上面示例中单个任务失败不会影响其他任务,因为
.catch()后仍会执行.finally()触发下一轮调度 -
支持取消(可选):可在 task 对象里加
signal或abort方法,但需任务函数本身配合(如fetch()支持 AbortSignal) -
想等全部完成?用
Promise.all(queue.results)不适用——因为 push 返回的是每个任务自己的 Promise,可收集它们:const promises = tasks.map(t => queue.push(t)),再Promise.all(promises)
更现代写法:用 async/await + 闭包状态
如果偏好 async 风格,也可以封装成函数形式,内部用闭包保存状态:
function createQueue(concurrency = 1) {
const tasks = [];
let running = 0;
const schedule = () => {
while (running < concurrency && tasks.length > 0) {
running++;
const [task, resolve, reject] = tasks.shift();
task()
.then(resolve)
.catch(reject)
.finally(() => {
running--;
schedule();
});
}
};
return {
add: (taskFn) => new Promise((resolve, reject) => {
tasks.push([taskFn, resolve, reject]);
schedule();
})
};
}

















