在for循环中对request-promise进行请求速率限制
用Promise控制API请求速率的解决方案
嘿,我完全懂你这个痛点——在循环里直接发起异步请求时,很容易一下子把所有请求都抛出去,分分钟触发API的速率限制。针对你用request-promise处理175个请求、每10秒最多40次的场景,咱们来聊聊两种靠谱的实现方式:
方案一:串行节流(简单可靠)
这种方式会逐个发送请求,每个请求之间严格间隔250ms,完美匹配每10秒40次的限制(40×250ms=10000ms)。优点是逻辑简单,不容易出错,适合对效率要求不是极致高的场景。
const rp = require('request-promise'); async function throttledRequests(itemIds, delayMs) { const results = []; // 用for...of配合await实现串行执行 for (const id of itemIds) { try { // 发起API请求 const response = await rp({ url: `https://api.example.com/items/${id}`, json: true // 自动解析JSON响应 }); results.push(response); // 最后一个请求不需要加延迟 if (id !== itemIds[itemIds.length - 1]) { await new Promise(resolve => setTimeout(resolve, delayMs)); } } catch (err) { // 单独处理每个请求的错误,避免一个失败导致全流程中断 console.error(`请求ID ${id} 失败:`, err.message); results.push({ id, error: err.message }); } } return results; } // 调用示例:替换成你的175个条目ID数组 const itemIds = Array.from({ length: 175 }, (_, i) => i + 1); throttledRequests(itemIds, 250) .then(allResults => { console.log('所有请求处理完成:', allResults); }) .catch(globalErr => { console.error('全局异常:', globalErr); });
方案二:批量并发+批次间隔(效率更高)
如果想更快完成所有请求,可以把请求分成批次——每批次最多40个请求(刚好是10秒内的限额),同一批次内的请求并发发送,批次之间间隔10秒。这样总耗时会比串行短很多(175个请求大概30多秒就能完成)。
const rp = require('request-promise'); async function batchThrottledRequests(itemIds, batchSize, batchDelayMs) { const results = []; // 把ID数组分割成多个批次 const batches = []; for (let i = 0; i < itemIds.length; i += batchSize) { batches.push(itemIds.slice(i, i + batchSize)); } // 逐个处理每个批次 for (const batch of batches) { // 并发处理当前批次的所有请求 const batchPromises = batch.map(id => rp({ url: `https://api.example.com/items/${id}`, json: true }) .catch(err => ({ id, error: err.message })) // 捕获单个请求错误 ); const batchResults = await Promise.all(batchPromises); results.push(...batchResults); // 最后一个批次不需要延迟 if (batch !== batches[batches.length - 1]) { await new Promise(resolve => setTimeout(resolve, batchDelayMs)); } } return results; } // 调用示例:每40个请求为一批,批次间隔10秒 const itemIds = Array.from({ length: 175 }, (_, i) => i + 1); batchThrottledRequests(itemIds, 40, 10000) .then(allResults => { console.log('所有请求处理完成:', allResults); }) .catch(globalErr => { console.error('全局异常:', globalErr); });
几个注意事项
- 错误处理:一定要给每个请求单独加
catch,不然某个请求失败会导致整个Promise.all或者串行流程中断。 - 速率限制细节:如果API的速率限制是「滚动窗口」(比如任意10秒内不超过40次),那批次间隔可以稍微调整(比如设为10500ms),避免因为批次处理耗时导致窗口重叠触发限制。
- 模块迁移提示:
request-promise已经被官方标记为弃用了,长期来看建议迁移到axios或者node-fetch,不过上面的代码逻辑完全可以适配这些新模块。
内容的提问来源于stack exchange,提问作者Ridhwaan Shakeel
相关产品推荐
相关产品推荐

