基于Promise的TaskRunner并发限制失效问题排查及优化咨询
并发限制TaskRunner问题排查与优化方案
一、原代码问题分析
- 任务计数逻辑错误:每次调用
run时直接给#taskCount加1,导致未执行的队列任务也被计入"运行中"。比如调用7次run后,#taskCount直接变成7,远超限制值3,后续的while循环条件#taskCount <= #limit永远不成立,队列中id-4到id-7的任务永远无法触发执行。 - 任务完成后无调度逻辑:任务执行完成的
then回调仅减少了#taskCount,但没有触发从队列中取出新任务执行。就算前3个任务全部完成,队列中的任务也不会自动启动,必须再次调用run才会检查队列。
二、优化实现方案
正确的核心逻辑应该是:维护当前正在运行的任务数,任务加入时先判断是否可直接启动;任务完成后自动从队列中取出下一个任务执行。
优化后的代码
class TaskRunner { #limit; #taskQueue = []; #runningCount = 0; // 仅记录当前正在运行的任务数 constructor(limit) { this.#limit = limit; } run(fn, id) { // 优先直接启动任务,超出限制则加入队列 if (this.#runningCount < this.#limit) { this.#startTask(fn, id); } else { this.#taskQueue.push({ task: fn, id }); } } #startTask(fn, id) { this.#runningCount++; fn(id) .then(() => { console.log(`Task Completed! ${id}`); }) .catch((err) => { console.error(`Task Failed! ${id}`, err); }) .finally(() => { this.#runningCount--; // 任务完成后自动调度队列中的下一个任务 if (this.#taskQueue.length > 0) { const { task, id } = this.#taskQueue.shift(); this.#startTask(task, id); } }); } } // 测试代码 const taskRunner = new TaskRunner(3); const task = (arg) => { return new Promise((resolve) => { setTimeout(() => { resolve(true); }, 2000); }); }; taskRunner.run(task, 'id-1'); taskRunner.run(task, 'id-2'); taskRunner.run(task, 'id-3'); taskRunner.run(task, 'id-4'); taskRunner.run(task, 'id-5'); taskRunner.run(task, 'id-6'); taskRunner.run(task, 'id-7');
优化点说明
- 修正计数逻辑:用
#runningCount仅统计当前正在执行的任务,避免把队列待执行任务误计入,确保并发限制判断准确。 - 自动任务调度:任务完成(无论成功或失败)的
finally回调中,自动从队列取出下一个任务启动,无需手动触发。 - 异常容错处理:增加
catch捕获任务执行错误,避免未处理的Promise异常导致程序崩溃。 - 代码结构解耦:把任务启动逻辑抽离到私有方法
#startTask中,提升代码可读性与可维护性。
内容的提问来源于stack exchange,提问作者xkeshav
相关产品推荐
相关产品推荐

