本文详解如何通过 promise.race 实现 fetch 请求的超时控制与备用链路降级,避免阻塞 ui,并确保在主 api 响应超 3 秒时无缝切换至备用接口。
在前端开发中,依赖第三方 API 时常面临网络延迟、服务不可用等问题。单纯用 if 判断无法实现“等待超时后执行另一请求”,因为 fetch() 是异步操作,其耗时不支持同步条件判断(如 if (timeTaken > 3000))。正确方案是利用 Promise.race() —— 它会返回首个 settled(fulfilled 或 rejected)的 Promise,从而天然支持超时竞争机制。
// 创建一个在指定毫秒后 reject 的超时 Promise
function timeout(ms, promise) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error(`Request timed out after ${ms}ms`)), ms)
)
]);
}
// 主逻辑:优先请求 link1,3 秒未响应则 fallback 到 link2
const requestOptions = {
method: 'GET',
headers: {
'apikey': 'your-api-key' // 请替换为实际 key
}
};
timeout(3000,
fetch('https://api.apilayer.com/exchangerates_data/latest?base=USD', requestOptions)
)
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
.then(data => {
console.log('✅ Primary API success:', data);
// 处理主数据逻辑(如渲染汇率)
})
.catch(error => {
console.warn('⚠️ Primary API failed or timed out:', error.message);
// 降级请求备用 API
return fetch('https://api.apilayer.com/fixer/latest?base=USD', requestOptions)
.then(res => {
if (!res.ok) throw new Error(`Fallback HTTP ${res.status}`);
return res.json();
})
.then(data => {
console.log('✅ Fallback API success:', data);
// 处理备用数据逻辑
})
.catch(err => {
console.error('❌ Both APIs failed:', err);
// 统一错误处理:提示用户、显示离线状态、启用缓存等
});
});
个请求或永远只走 if 分支,完全违背设计意图。通过该模式,你不仅能优雅解决超时降级问题,还能提升应用健壮性与用户体验——这才是现代前端异步容错的正确实践。