如何使用异步迭代器实现集合分片顺序映射,规避API请求过载报错
基于异步迭代器的API并发请求限流实现
完全可以基于异步迭代器实现符合要求的方案,同时保留极高的扩展性,具体实现如下:
前置工具函数
// 通用休眠工具 const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
核心封装实现
/** * 批量为event挂载详情,内置分片+休眠限流 * @param {Array} events 原始event集合 * @param {Object} options 配置项(可选) * @param {Number} options.chunkSize 单批并发请求数,默认1000 * @param {Number} options.sleepMs 批间休眠时长,默认4000ms * @param {Function} options.detailMapper 单条event的详情映射函数,默认调用event.getEventDetails() * @returns {Promise<Array>} 挂载完详情的完整event集合 */ async function mapEventsWithDetails(events, options = {}) { // 配置默认值 const { chunkSize = 1000, sleepMs = 4000, detailMapper = async (event) => ({ ...event, ...await event.getEventDetails() }) } = options; const total = events.length; const result = []; // 异步迭代器实现分片处理逻辑 async function* chunkGenerator() { for (let currentIdx = 0; currentIdx < total; currentIdx += chunkSize) { // 取出当前分片 const chunk = events.slice(currentIdx, currentIdx + chunkSize); // 并发处理当前分片所有请求 const processedChunk = await Promise.all(chunk.map(detailMapper)); yield processedChunk; // 非最后一批才休眠,避免结束时无意义等待 if (currentIdx + chunkSize < total) { await sleep(sleepMs); } } } // 消费异步迭代器,收集所有分片结果 for await (const processedChunk of chunkGenerator()) { result.push(...processedChunk); } return result; }
使用方式
完全符合你要求的调用形式:
// 最简调用,使用默认配置 const eventsWithDetails = await mapEventsWithDetails(events);
也可以根据实际API限流规则灵活调整参数:
// 自定义配置:每200条请求休眠2秒,自定义映射逻辑 const customEvents = await mapEventsWithDetails(events, { chunkSize: 200, sleepMs: 2000, detailMapper: async (event) => { const details = await customApi.getDetail(event.id); return { ...event, details }; } });
原疑问解答
你之前代码里疑惑的「如何对外返回完整result」的问题,不需要依赖异步生成器的返回值,只需要在封装函数内部声明结果数组,通过for await...of消费迭代器时逐片收集结果,最后统一返回即可,逻辑更清晰也更容易做错误处理。
扩展性说明
这个方案还可以很方便的扩展更多能力:
- 分片失败重试:某一批请求失败时,可以单独重试当前分片,不需要全量重跑
- 进度回调:可以在配置项加onProgress参数,每处理完一批就回调通知当前进度
- 并发粒度控制:如果需要比分片更细的并发控制,也可以在单分片内替换Promise.all为限流器实现,适配更严格的API限流规则
内容的提问来源于stack exchange,提问作者James Jr.
相关产品推荐
相关产品推荐

