Promise 早已成为我们处理并发任务不可或缺的利器,其中,Promise.all 和 Promise.race 是我们最熟悉的两个“老朋友”。Promise.all 会等待所有任务完成,而 Promise.race 会在任意一个任务完成(无论成功或失败)时立即返回结果。然而,在多数场景下,Promise.race 的这种特性并非我们所需,甚至可能是一个陷阱。
Promise.race 的问题所在
Promise.race 的问题在于,它追求的是最快的“响应”,而非最快的“成功”。
来看一个例子:
const promiseFailFast = new Promise((resolve, reject) => {
// 500ms 后失败
setTimeout(() => reject('请求A失败'), 500);
});
// 堆代码 duidaima.com
const promiseSucceedSlow = new Promise((resolve, reject) => {
// 1000ms 后成功
setTimeout(() => resolve('请求B成功'), 1000);
});
Promise.race([promiseFailFast, promiseSucceedSlow])
.then(value => {
console.log('成功:', value);
})
.catch(error => {
console.error('失败:', error); // 输出: 失败: 请求A失败
});
在这个例子中,尽管我们有一个本可以成功的请求 promiseSucceedSlow,但因为 promiseFailFast 在 500 毫秒时率先失败,Promise.race 立刻以失败告终。我们的程序与“成功”失之交臂,这显然不是我们想要的“容错”或“择优”逻辑。
精准打击:Promise.any 登场
Promise.any 的设计初衷正是为了解决上述问题。其规则清晰明了,完美符合我们的直觉:Promise 集合中一旦有一个成功,它就会立即以那个成功的值 resolve。让我们用 Promise.any 重写上面的例子:

看!即使 promiseFailFast 先失败了,Promise.any 也会耐心地忽略它,继续等待,直到 promiseSucceedSlow 在 1000 毫秒时成功返回。我们得到了期望的结果,这才是真正的“容错”和“冗余”设计。
Promise.any 的设计使其在以下场景中大放异彩:
.资源冗余与加速:例如从最快的 CDN 节点加载资源,以提升用户体验
.API 优雅降级:API 为了兼容旧的 V1 版本,可以优先尝试 V2,如果失败(或不存在),再自动使用 V1
Promise.any 并不是要完全“抛弃” Promise.race。Promise.race 在实现“超时控制”等场景中依然有其价值。例如: Promise.race([fetch('...'), timeout(5000)]) 仍然是判断一个请求是否超时的经典模式。但是,对于“从多个异步任务中获取第一个成功结果”这一普遍需求,Promise.any 提供了原生、精准且优雅的解决方案。