一、Promise.any
Promise.any
是 JavaScript 中用于处理多个 Promise 的方法,它会返回 第一个成功解析(fulfilled)的 Promise 的结果,只有当所有 Promise 都失败时才会抛出错误。
1.1、成功案例
const p1 = Promise.reject('Error1');
const p2 = new Promise(res => setTimeout(res, 500, 'Fast'));
const p3 = new Promise(res => setTimeout(res, 1000, 'Slow'));
Promise.any([p1, p2, p3])
.then(console.log) // 'Fast'(500ms)
.catch(e => console.log(e.errors)); // 不会执行
1.2、全失败案例
const errors = [
Promise.reject('ErrorA'),
Promise.reject('ErrorB')
];
Promise.any(errors)
.catch(e => {
console.log(e instanceof AggregateError); // true
console.log(e.errors); // ['ErrorA', 'ErrorB']
});
二、Promise.race
Promise.race 是 JavaScript 中用于处理多个 Promise 的竞速方法,它会返回 第一个完成(无论成功或失败)的 Promise 的结果。
2.1、 首个成功完成的 Promise
const fast = new Promise(resolve =>
setTimeout(resolve, 100, '快速成功')
);
const slow = new Promise(resolve =>
setTimeout(resolve, 500, '慢速成功')
);
Promise.race([fast, slow])
.then(result => console.log(result)); // 100ms 后输出:"快速成功"
2.2、首个失败完成的 Promise
const success = new Promise(resolve =>
setTimeout(resolve, 200, '成功')
);
const failure = new Promise((_, reject) =>
setTimeout(reject, 100, '失败')
);
Promise.race([success, failure])
.catch(error => console.log(error)); // 100ms 后输出:"失败"
三、使用场景
1. Promise.race
使用场景
场景特点
- 需要 竞速,即优先响应第一个完成的结果(无论成功或失败)。
- 适用于对响应速度敏感,且允许容忍部分失败的场景。
具体场景
1.1 超时控制
需求:为异步操作(如 API 请求)设置超时,避免长时间等待。
实现:将业务 Promise 与一个定时器 Promise 放入 race
,若超时先完成,则中断操作。
const fetchData = () => {
// 模拟数据请求(假设需要 3 秒)
return new Promise((resolve) =>
setTimeout(() => resolve("Data loaded"), 3000)
);
};
// 设置 2 秒超时
const timeout = new Promise((_, reject) =>
setTimeout(() => reject("Request timeout"), 2000)
);
Promise.race([fetchData(), timeout])
.then(console.log) // 若 2 秒内未完成,触发 timeout
.catch(console.log); // 输出 "Request timeout"
1.2 多源竞速响应
需求:从多个数据源获取同一资源,优先使用最快响应的(无论成功与否)。
示例:两个天气 API 接口,选择最快返回的结果(可能是成功或失败)。
const api1 = fetch('https://weather-api1.com').then(r => r.json());
const api2 = fetch('https://weather-api2.com').then(r => r.json());
Promise.race([api1, api2])
.then(data => displayWeather(data))
.catch(() => showError("Failed to load weather"));
2. Promise.any
使用场景
场景特点
- 需要 至少一个成功,忽略失败,直到第一个成功结果。
- 适用于资源冗余、故障容忍的场景,优先保证可用性。
具体场景
2.1 多 CDN 资源加载
需求:从多个 CDN 加载静态资源(如 JS 库),使用第一个成功加载的。
实现:即使某些 CDN 不可用,也能通过其他备用源确保成功。
const cdnUrls = [
'https://cdn1.example.com/react.js',
'https://cdn2.example.com/react.js',
'https://cdn3.example.com/react.js'
];
Promise.any(cdnUrls.map(url =>
fetch(url).then(res => res.text())
))
.then(code => injectScript(code))
.catch(() => alert("All CDNs failed!"));
2.2 服务高可用(故障转移)
需求:调用多个备用服务(如支付网关),只要有一个成功即继续流程。
示例:用户支付时尝试多个支付渠道,直到有一个成功。
const paymentGateways = [
payWithStripe(order),
payWithPayPal(order),
payWithAlipay(order)
];
Promise.any(paymentGateways)
.then(receipt => showSuccess(receipt))
.catch(errors =>
alert(`All payments failed: ${errors.errors.join(', ')}`)
);
四、总结
特性 | Promise.race | Promise.any |
---|---|---|
关注点 | 第一个完成的(无论成功或失败) | 第一个成功的(忽略失败,直到有成功) |
成功时的行为 | 返回第一个完成的结果(可能是成功或失败) | 返回第一个成功的结果 |
全失败时的行为 | 返回第一个错误 | 抛出 AggregateError (包含所有错误) |
引入版本 | ES6 (ES2015) | ES2021 |