本文介绍如何将一组 promise 按固定批次(如每 2 个)分组,并确保前一批全部完成后再执行下一批,适用于 api 限流、资源节制等场景。
在实际开发中(尤其是调用后端接口时),我们常需避免并发请求过多导致服务端压力过大或触发限流。此时,简单使用 Promise.all(promises) 会一次性发起所有请求;而逐个 await 又效率过低。理想方案是:分批并发执行,批间串行等待——即每批运行 n 个 Promise,全部 resolve 后再启动下一批。
以下是一个简洁、可复用的实现:
async function runInBatches(promiseFactories, batchSize = 2) {
for (let i = 0; i < promiseFactories.length; i += batchSize) {
const batch = promiseFactories.slice(i, i + batchSize);
// 批内并发执行,批间 await 阻塞
await Promise.all(batch.map(fn => fn()));
console.log(`✅ Batch [${i}–${Math.min(i + batchSize - 1, promiseFactories.length - 1)}] completed`);
}
}
// 示例:模拟 6 个 axios 请求(注意:传入的是函数,而非已执行的 Promise)
const apiCalls = [
() => axios.post('/api', { id: 1 }),
() => axios.post('/api', { id: 2 }),
() => axios.post('/api', { id: 3 }),
() => axios.post('/api', { id: 4 }),
() => axios.post('/api', { id: 5 }),
() => axios.post('/api', { id: 6 })
];
// 每批并发 2 个请求,共 3 轮
await runInBatches(apiCalls, 2);? 关键设计说明:
- ✅ 传入的是 Promise 工厂函数(() => axios.post(...)),而非已创建的 Promise,避免请求提前发起;
- ✅ 使用 for 循环 + await Promise.all(...) 实现“批内并行、批间串行”;
- ✅ slice() 安全处理末尾不足 batchSize 的情况(自动截断,无越界风险);
- ⚠️ 若
某批中任一 Promise reject,整个 Promise.all 将拒绝,需根据业务需求添加错误处理(如 Promise.allSettled 或 try/catch 包裹)。
? 进阶建议:
- 如需容错(单个失败不影响整批),可改用 Promise.allSettled;
- 如需动态控制并发数(如基于令牌桶),可结合 p-limit 等工具库;
- 在 React 或 Vue 中调用时,注意避免在渲染函数中直接 await,应封装为事件处理器或 useEffect 副作用。
该模式兼顾效率与可控性,是前端批量请求调度的经典实践。

某批中任一 Promise reject,整个 Promise.all 将拒绝,需根据业务需求添加错误处理(如 Promise.allSettled 或 try/catch 包裹)。






