Promise.race 实现请求超时的核心是并行执行真实请求与定时 reject 的 Promise,谁先完成即采用其结果;若定时器先触发则判定超时,需配合 AbortController 才能真正中断网络请求而非仅忽略结果。

用 Promise.race 实现请求超时告警,核心思路是:把真实请求 Promise 和一个定时 reject 的 Promise 一起传入 race,谁先完成就用谁的结果——如果定时器先触发,就说明超时了。
基础实现:封装带超时的 fetch 请求
下面是一个通用写法,支持任意 Promise(比如 fetch、axios):
function timeoutPromise(promise, ms) {
return Promise.race([
promise,
new Promise((_, reject) => {
setTimeout(() => reject(new Error(`请求超时(${ms}ms)`)), ms);
})
]);
}
// 使用示例
timeoutPromise(fetch('/api/data'), 5000)
.then(res => res.json())
.then(data => console.log('成功:', data))
.catch(err => console.warn('失败:', err.message));
更健壮的版本:区分超时和其他错误
实际项目中建议明确判断错误类型,避免把网络错误误判为超时:
- 给超时错误加自定义标识(如
isTimeout = true),方便统一处理 - 保留原始 Promise 的 abort 能力(如
AbortController)可选增强
function withTimeout(promise, ms) {
let timeoutId;
const timeout = new Promise((_, reject) => {
timeoutId = setTimeout(
() => reject(Object.assign(new Error(`请求超时(${ms}ms)`), { isTimeout: true })),
ms
);
});
return Promise.race([promise, timeout]).finally(() => clearTimeout(timeoutId));
}
配合 AbortController 主动中断(推荐用于 fetch)
现代浏览器中,fetch 支持 signal,比单纯靠 race 更精准(能真正终止网络请求,而非只拒绝 Promise):
立即学习“Java免费学习笔记(深入)”;
function fetchWithTimeout(url, options = {}, ms = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), ms);
return fetch(url, {
...options,
signal: controller.signal
}).finally(() => clearTimeout(timeoutId));
}
注意:controller.abort() 会触发 fetch 抛出 AbortError,需在 catch 中识别处理。
常见坑点提醒
-
Promise.race不会取消已发起的请求,只是忽略后续结果;想真正中断请用AbortController - 超时时间设太短容易误伤正常慢网用户,建议结合业务场景(如 3s–10s)
- 多个并发请求都加超时,别忘了每个都要独立计时,避免共用同一个定时器
不复杂但容易忽略细节。关键在“谁先完成谁生效”,再补上可读的错误提示和可控的中断机制,就能稳稳落地。


















