JavaScript如何为pending状态的fetch请求设置超时跳过无响应节点
Fetch请求3秒超时自动跳过无响应节点实现方案
核心实现逻辑
原生fetch API没有内置超时中断机制,针对无响应请求挂起的问题,可通过两个原生能力组合解决:
- 用
AbortController生成请求中断信号,传入fetch配置项,支持主动终止未完成的请求 - 用
Promise.race()做超时竞速:同时发起fetch请求和超时倒计时,3秒内请求未返回就主动触发中断,直接跳过对应节点
完整可运行代码
// 节点列表 let nodes = [ { "address": { "hostname": "192.168.1.1", "port": 31350 } }, { "address": { "hostname": "192.168.1.2", "port": 31350 } } ] /** * 拉取单个节点状态 * @param {string} hostname 节点IP * @param {number} port 节点端口 * @param {number} timeout 超时时间,默认3000ms * @returns 节点状态数据,失败返回null */ async function fetchNodes(hostname, port, timeout = 3000) { // 每个请求单独创建中断控制器,避免多请求互相干扰 const controller = new AbortController(); const signal = controller.signal; let timeoutId = null; try { const response = await Promise.race([ fetch(`https://${hostname}:${port}/getstatus`, { method: 'post', // 原代码中body变量需提前定义,此处保留原有传参逻辑 body: JSON.stringify(body), headers: { 'Content-Type': 'application/json' }, signal: signal }), new Promise((_, reject) => { timeoutId = setTimeout(() => reject(new Error('请求超时无响应')), timeout); }) ]); // 修复原代码漏写await的问题,否则会拿到pending状态的Promise const data = await response.json(); console.log(`节点${hostname}:${port}数据拉取成功`, data); return data; } catch (err) { // 统一捕获超时、网络不通、接口报错等所有异常,直接跳过当前节点 console.log(`节点${hostname}:${port}拉取失败,已跳过:${err.message}`); return null; } finally { // 清除定时器避免内存泄漏 if (timeoutId) clearTimeout(timeoutId); } } // 批量发起节点请求 nodes.forEach(function(entry) { fetchNodes(entry.address.hostname, entry.address.port); })
注意事项
- 禁止多个请求共用同一个AbortController实例,否则单个请求超时会中断所有正在进行的请求
- 如果需要等所有节点请求全部结束(无论成功失败)再执行后续逻辑,可将批量调用逻辑改为:
const allResult = await Promise.allSettled( nodes.map(entry => fetchNodes(entry.address.hostname, entry.address.port)) ) // 后续统一处理allResult即可 AbortController为现代JS运行时原生API,Chrome 66+、Firefox 57+、Node.js 15+均默认支持,无需引入第三方依赖- 超时时间可通过fetchNodes的第三个参数自定义,默认值为3000毫秒即3秒
内容的提问来源于stack exchange,提问作者masch1na
相关产品推荐
相关产品推荐

