为Promise.all序列添加延迟,解决API请求EAI_AGAIN错误
解决API请求限流导致的
getaddrinfo EAI_AGAIN错误 首先,咱们先理清楚问题:你遇到的getaddrinfo EAI_AGAIN虽然表面是DNS解析失败,但结合你说的并发请求场景,大概率是API提供商的限流策略(或者DNS层面的请求频率限制)被触发了——当你同时发起太多请求时,对方的服务器/DNS服务直接拒绝了部分请求的解析。
你之前尝试加延迟没成功,核心问题出在延迟的实现方式不对,而且请求依然是并发发起的,根本没达到错开请求的目的。先看看你现有代码的问题:
- 原生
fetch不支持回调参数(你写的fetch(url, (err, res) =>...是错误用法,fetch返回Promise,需要用.then()或者await处理) - 如果是批量调用你的
delayedFetch,比如用urls.map(url => delayedFetch(url)),那所有的setTimeout会同时启动,延迟结束后还是一堆请求同时发出去,和没加延迟没啥区别。
正确的解决方案:串行+间隔延迟
要真正避开限流,得让请求逐个串行发起,前一个请求完成(包括等待延迟、请求、响应处理)后,再发起下一个请求。下面给你修正后的代码:
class someClass { // 修正后的延迟请求方法 async delayedFetch(url, delayMs = 1200) { // 先等待指定延迟时间 await new Promise(resolve => setTimeout(resolve, delayMs)); try { // 正确使用fetch的Promise API const response = await fetch(url); // 先检查HTTP响应状态 if (!response.ok) { throw new Error(`请求失败:HTTP状态码 ${response.status}`); } // 假设API返回JSON,根据实际格式调整(比如text()) const data = await response.json(); return data; } catch (error) { console.error(`获取 ${url} 时出错:`, error); // 可以选择抛出错误让上层处理,或者返回错误标记 throw error; } } // 批量处理所有URL的方法(串行执行) async fetchAllUrls(urlList, delayBetweenRequests = 1200) { const results = []; // 用for...of循环+await实现串行 for (const url of urlList) { try { const result = await this.delayedFetch(url, delayBetweenRequests); results.push({ url, data: result, success: true }); } catch (err) { // 记录错误,继续处理下一个URL results.push({ url, error: err.message, success: false }); } } return results; } }
为什么这个方案有效?
for...of循环配合await会强制等待当前请求完全完成(包括延迟时间和请求过程),才会进入下一次循环处理下一个URL,彻底避免了并发请求。- 修正了
fetch的用法,正确处理了响应和错误,不会因为Promise处理不当导致逻辑异常。
额外建议
- 可以根据API文档(如果有的话)调整
delayBetweenRequests的时长,比如如果限流是每分钟允许60次请求,那间隔设为1100ms(比1000ms多一点,留缓冲)更稳妥。 - 如果担心串行太慢,也可以实现并发控制(比如同时最多发起3个请求,每个请求之间加延迟),但串行是最稳妥的方式,尤其是在不确定限流阈值的时候。
内容的提问来源于stack exchange,提问作者S. Schenk
相关产品推荐
相关产品推荐

