JavaScript中实现Promise缓冲池并发:维持最大3-4个并发执行
实现Promise的动态并发控制(保持3-4个并发)
你现在的需求是把“批量等待一组完成再启动下一组”改成“一个任务完成就立刻补上新任务,始终维持最多3个并发”,这其实是动态并发池的场景,比固定批量的Promise.all更高效——尤其是当单个任务耗时差异较大时,能避免因某几个慢任务拖慢整体进度。
核心思路
我们可以维护两个关键集合:一个存放待执行的任务队列,另一个跟踪正在运行的Promise:
- 先启动前3个任务,把它们加入“运行中Promise”集合;
- 每当其中一个Promise完成(成功或失败),就从运行集合里移除它,同时从任务队列里取出下一个任务执行;
- 重复这个补位过程,直到任务队列空了,且所有运行中的任务都完成。
代码实现(以并发数3为例)
这里提供一个通用的工具函数,你可以直接复用:
async function runWithConcurrentLimit(tasks, limit = 3) { // 复制任务列表,避免修改原数组 const taskQueue = [...tasks]; const runningPromises = []; const results = []; // 定义单个任务的处理逻辑 async function handleNextTask() { if (taskQueue.length === 0) return; // 取出队列第一个任务并执行 const task = taskQueue.shift(); try { const result = await task(); results.push(result); } catch (err) { // 可根据需求调整错误处理:比如单独收集错误、或直接抛出终止所有任务 results.push({ error: err }); } finally { // 任务完成后,从运行列表移除自己,再启动下一个任务 const idx = runningPromises.indexOf(handleNextTask); if (idx !== -1) runningPromises.splice(idx, 1); await handleNextTask(); } } // 启动初始的limit个任务 const initialCount = Math.min(limit, taskQueue.length); for (let i = 0; i < initialCount; i++) { const promise = handleNextTask(); runningPromises.push(promise); } // 等待所有启动的任务全部完成 await Promise.all(runningPromises); return results; }
使用方式
假设你的目标函数是fetchData(param)(返回Promise),现在有一堆参数需要执行:
// 把每个参数包装成无参任务函数,方便队列统一处理 const params = [1, 2, 3, 4, 5, 6, 7, 8, 9]; const tasks = params.map(param => () => fetchData(param)); // 调用工具函数,设置并发数为3(改成4就是最多4个并发) runWithConcurrentLimit(tasks, 3).then(finalResults => { console.log('所有任务执行完毕:', finalResults); });
关键细节说明
- 任务包装:把带参数的函数调用包装成无参函数,这样队列里的任务可以直接执行,不用额外传递参数;
- 错误隔离:用
try/catch捕获单个任务的错误,避免某一个任务失败导致整个并发池崩溃,你可以根据业务需求调整错误处理逻辑; - 动态补位:每个任务完成后(无论成功失败),都会立刻启动队列里的下一个任务,始终让并发数维持在设定的上限;
- 最终等待:用
Promise.all(runningPromises)确保所有启动的任务都执行完毕,再返回最终结果集合。
如果要调整并发数,只需要修改limit参数为4即可,非常灵活。
内容的提问来源于stack exchange,提问作者Pjotr Raskolnikov
相关产品推荐
相关产品推荐

