用 async/await 配合 promise.race 实现接口超时,核心是让“请求 promise”和“超时 promise”赛跑,谁先完成就用谁的结果——超时的则抛出错误,从而触发 catch 或 try/catch 中的提示逻辑。

用 async/await 配合 Promise.race 实现接口超时,核心是让“请求 Promise”和“超时 Promise”赛跑,谁先完成就用谁的结果——超时的则抛出错误,从而触发 catch 或 try/catch 中的提示逻辑。
构造一个可取消的超时 Promise
超时逻辑不能只靠 setTimeout 简单 reject,否则原请求还在后台运行,浪费资源且可能干扰后续逻辑。推荐封装一个带清理能力的超时函数:
- 用
AbortController主动中断 fetch 请求(现代浏览器支持) - 超时 Promise 在触发时调用
abort(),确保请求真正中止 - 避免内存泄漏:超时后若请求仍 pending,应丢弃其结果(不处理 resolve/reject)
用 Promise.race 包裹请求和超时
Promise.race 返回最先 settled(fulfilled 或 rejected)的那个 Promise。把 fetch 请求和超时 Promise 一起传入,就能自然实现“谁快谁赢”:
- 请求在超时前成功 → race 返回 fetch 的 resolved 值
- 超时先触发 → race 返回超时 Promise 的 rejected 状态,抛出
"Request timeout"类错误 - 注意:race 不会自动取消另一个 Promise,所以必须配合
AbortController手动中断
在 async 函数中统一处理超时异常
直接在 try/catch 里 await race 结果,捕获超时错误并展示用户提示:
- catch 到的错误建议区分类型(如检查
error.name === 'AbortError'或自定义error.code === 'TIMEOUT') - 避免全局 alert,推荐用轻量 toast 或状态字段(如
loading = false, error = '网络超时,请重试') - 不要在 catch 里 silent 吞掉错误,至少打日志:
console.warn('API timeout:', url)
完整可复用示例
以下是一个生产可用的封装:
async function fetchWithTimeout(url, options = {}, timeoutMs = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(timeoutId);
return response;
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw Object.assign(new Error('Request timeout'), { code: 'TIMEOUT' });
}
throw error;
}
}
// 使用方式
async function loadData() {
try {
const res = await fetchWithTimeout('/api/data', {}, 3000);
const data = await res.json();
console.log(data);
} catch (err) {
if (err.code === 'TIMEOUT') {
alert('请求超时,请检查网络');
} else {
alert('请求失败:' + err.message);
}
}
}Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











