如何使用async/await实现Node.js API请求分块并行处理
问题根因
你最初的串行实现每次仅会等待上一个请求完全响应后才发起下一个请求,在单次请求平均耗时1秒的场景下,处理10万个ID需要近28小时,完全没有用上接口每秒25次的请求配额。按照限流阈值计算,理论最优处理时长仅为100000/25 = 4000秒(约1.1小时)。
并发控制实现方案
完全可以实现任意时刻固定保持N个请求并行的效果,核心逻辑非常简单:
- 启动时直接发起N个请求
- 只要任意一个请求完成,立刻从待处理ID队列中取下一个ID发起新请求
- 直到所有ID处理完成、所有在途请求全部返回为止
这种模式既不会突发超量请求触发接口限流,也不会浪费请求配额,刚好打满接口允许的速率上限。
可直接复用的代码
我们把并发数N设置为25,刚好匹配你当前接口的限流规则:
const ids = [...Array(100000).keys()]; // 并发数设为25,单次请求平均耗时1秒时刚好卡满每秒25次的限流阈值 const MAX_CONCURRENT = 25; // 单ID请求逻辑 const downloadTodo = async (id) => { const resp = await fetch(`https://somapi.com/todo/${id}`); if (!resp.ok) throw new Error(`请求ID${id}失败,状态码${resp.status}`); return resp.json(); }; const downloadTodos = async (ids) => { const result = []; // 待处理ID的指针,递增取值避免重复请求 let cursor = 0; // 单个工作协程:不停取未处理的ID发请求,直到所有ID处理完 const runWorker = async () => { while (cursor < ids.length) { const currentId = ids[cursor]; cursor++; try { const data = await downloadTodo(currentId); result.push({ id: currentId, success: true, data }); } catch (err) { result.push({ id: currentId, success: false, err }); // 如需失败重试,在这里加重试逻辑即可,不会破坏并发控制 } } }; // 启动指定数量的工作协程并行处理,等待所有协程执行完毕 const workers = Array.from({ length: MAX_CONCURRENT }, () => runWorker()); await Promise.all(workers); return result; };
补充说明
- 上述实现的并发数是严格可控的,任意时刻在途请求数最多为你设置的
MAX_CONCURRENT值,不会出现一次性发起成百上千个请求打崩接口、触发429限流的问题。 - 如果你的接口限流是严格的固定窗口/滑动窗口计数(而非基于并发的QPS限制),可以额外加一层简单的节流逻辑:每发送25个请求就固定等待1秒即可。在你当前单次请求平均耗时1秒的场景下,25并发的实现已经自然满足速率要求,不需要额外加等待。
- 如果需要按ID顺序返回结果,只需要把
result从数组改成按ID索引存储即可,不需要调整核心并发逻辑。
内容的提问来源于stack exchange,提问作者ajthinking
相关产品推荐
相关产品推荐

