Promise.race适用于多网络请求“抢答”,取首个settled结果,常用于选最快API端点或主备服务探测;需加独立超时控制,避免慢请求阻塞判定。

Promise.race 适合在多个网络请求中“抢答”——谁先返回(无论成功或失败),就用谁的结果,常用于选最快可用的 API 端点、CDN 或备用服务。
核心逻辑:并发发起请求,取首个 settled 结果
它不等全部完成,也不过滤错误;只要有一个 Promise 进入 fulfilled 或 rejected 状态,Promise.race 就立即结束并返回该结果。因此需注意:如果第一个请求快速失败(如 404、超时、网络中断),你拿到的就是错误,而非后续更快的成功响应。
- 适合场景:有多个等效后端(如多地部署的同接口)、DNS 轮询、主备服务探测
- 不适合场景:必须确保成功才继续(此时应选
Promise.any或手动兜底) - 关键提醒:务必为每个请求加独立超时控制,否则慢请求会拖住 race 判定(因 pending 状态不会触发 race 结束)
带超时保护的双线路请求示例
以下同时请求国内和海外两个镜像接口,并限制每个请求最多 3 秒:
function timeout(ms, promise) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms)
)
]);
}
const apiCN = timeout(3000, fetch('https://api-cn.example.com/data'));
const apiUS = timeout(3000, fetch('https://api-us.example.com/data'));
Promise.race([apiCN, apiUS])
.then(res => res.json())
.then(data => console.log('最快响应:', data))
.catch(err => console.error('所有线路均不可用或超时:', err));
处理失败优先问题:用封装函数跳过 rejected
若希望“忽略第一个失败,等待第一个成功”,Promise.race 本身做不到,但可配合 Promise.allSettled 或自定义策略。更轻量的做法是:把每个请求包装成“永远 resolve”的 Promise,内部自行处理错误:
立即学习“Java免费学习笔记(深入)”;
function safeFetch(url) {
return fetch(url).then(res => res.ok ? res.json() : Promise.reject(res.status));
}
// 包装为“失败也 resolve”,但携带错误标记
function tryFetch(url) {
return fetch(url)
.then(res => res.ok ? Promise.resolve({ success: true, data: res }) : Promise.resolve({ success: false, error: res.status }))
.catch(err => Promise.resolve({ success: false, error: err.message }));
}
Promise.race([tryFetch('https://a.example.com'), tryFetch('https://b.example.com')])
.then(result => {
if (result.success) {
console.log('选中线路返回成功:', result.data);
} else {
console.warn('该线路失败,但 race 已结束 —— 此时需额外逻辑重试或降级');
}
});
实际使用建议
- 线路地址应语义等价(相同参数、相同返回结构),避免结果不可互换
- 生产环境建议搭配简单日志:记录哪条线路胜出、耗时多少,便于监控线路质量
- 不要滥用:高频调用 race 多个公网请求可能增加服务器压力,可考虑客户端缓存上一次胜出线路 30–60 秒
- 注意 CORS 和证书一致性,不同域名可能触发预检或证书警告,影响“谁先返回”判断


















