JavaScript Promise.any 怎样获取第一个成功结果
来源:17golang原创
时间:2026-10-27 00:59:36 437浏览 收藏
当页面需要从多个接口、缓存层或备用资源中先拿到一个可用结果时,Promise.any() 是最直接的选择:它等待输入中第一个 fulfilled 的 Promise,并把那个成功值交给调用方;先 reject 的候选不会让整体立即失败。要注意,所有候选都失败时才会进入 AggregateError,而已经发出的其他任务也不会因为某个结果先返回就自动取消。
Promise.any()看的是“第一个成功完成”,不是数组中的第一个元素。- 全部失败或传入空 iterable 时,捕获
AggregateError,用errors定位原因。 - 它与
Promise.race()、Promise.all()的成功条件不同,也不负责取消剩余请求。
const value = await Promise.any(candidates)就能拿到第一个 fulfilled 值;若没有任何候选成功,再在catch中处理AggregateError。
把候选请求交给 Promise.any
调用方式是把一组 Promise 或 thenable 放入 iterable。数组位置只决定输入顺序,不决定哪个值获胜;真正决定结果的是哪个 Promise 先 fulfilled。下面用三个延迟不同的候选模拟多源读取:
function delayedValue(value, delay, shouldFail = false) {
return new Promise((resolve, reject) => {
// 用延迟模拟不同数据源的响应速度,失败候选只影响自己的状态。
setTimeout(() => {
if (shouldFail) {
reject(new Error(`${value} 暂不可用`));
return;
}
resolve(value);
}, delay);
});
}
async function pickFirstSuccess() {
const candidates = [
delayedValue("主接口", 180, true),
delayedValue("边缘缓存", 80),
delayedValue("备用接口", 240),
];
try {
// Promise.any 只接收首个 fulfilled 值,不等待数组中的所有成功结果。
const value = await Promise.any(candidates);
return value;
} catch (error) {
// 只有全部候选失败时才会走这里;保留原始错误供上层记录。
throw error;
}
}
pickFirstSuccess().then((value) => {
console.log(value); // 边缘缓存
});
这个例子里“主接口”先失败,“边缘缓存”随后成功,所以结果是“边缘缓存”。即使“备用接口”仍在等待,组合 Promise 也已经 fulfilled。真实项目中可以把 fetch()、缓存读取函数或其他异步封装直接放进 candidates,但要保证每个候选在失败时真正 reject,而不是用一个错误对象 fulfilled,否则它会被当成成功值。

全部失败时用 AggregateError 找原因
如果所有输入都 reject,Promise.any() 才会拒绝。捕获对象是 AggregateError,其中的 errors 数组按传入 Promise 的顺序保存原因,而不是按实际完成的先后排列。这个特性适合把每个来源的失败信息映射回来源名称:
async function readFromFallbacks() {
const names = ["主接口", "边缘缓存", "备用接口"];
const candidates = names.map((name, index) => {
return Promise.reject(new Error(`${name} 返回失败码 ${500 + index}`));
});
try {
// 三个输入全部 reject,Promise.any 才会抛出 AggregateError。
return await Promise.any(candidates);
} catch (error) {
if (error instanceof AggregateError) {
// errors 与 names 同序,可稳定生成逐来源的诊断信息。
return error.errors.map((reason, index) => ({
source: names[index],
message: reason.message,
}));
}
throw error;
}
}
不要只把 AggregateError 转成一句“全部失败”。生产日志至少应保留来源名和错误原因;如果传入空数组,也会走失败分支,因此在构造候选列表前可以先判断是否为空,并给调用方一个更明确的业务提示。

Promise.any、Promise.race 与 Promise.all 怎么选
| 组合器 | 何时结束 | 结果语义 | 常见用途 |
|---|---|---|---|
Promise.any | 首个 fulfilled,或全部 reject | 一个成功值;全失败为 AggregateError | 多源兜底、先可用资源 |
Promise.race | 首个 settled | 第一个成功或失败都决定结果 | 超时竞争、首个状态 |
Promise.all | 全部 fulfilled,或一个 reject | 按输入顺序返回全部成功值 | 必须齐全的并行任务 |
如果“第一个返回的结果”可能是失败,选 race;如果必须拿齐所有数据,选 all。如果只关心任意一个成功来源,才用 any。另外,any fulfilled 后,剩余请求仍可能消耗网络和服务端资源,需要取消时要把 AbortController 设计进每个候选任务,并在业务层决定何时调用 abort()。
常见问题
Promise.any 会返回数组中第一个 Promise 吗?
不会。数组位置只用于建立输入顺序;返回的是运行过程中第一个 fulfilled 的值。
有一个 Promise reject 会导致 Promise.any 失败吗?
不会。只要仍有候选最终 fulfilled,先发生的 reject 就会被忽略;只有全部候选 reject 才失败。
Promise.any 成功后会自动停止其他请求吗?
不会。它只结束组合结果,不会取消底层操作;需要节省资源时应额外设计取消信号。
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
260 收藏
-
118 收藏
-
410 收藏
-
202 收藏
-
300 收藏
-
209 收藏
-
211 收藏
-
446 收藏
-
498 收藏
-
253 收藏
-
221 收藏
-
157 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习