当前位置:首页 > 文章列表 > 文章 > 前端 > JavaScript Promise.any 怎样获取第一个成功结果

JavaScript Promise.any 怎样获取第一个成功结果

来源:17golang原创 2026-10-27 00:59:36 0浏览 收藏

当页面需要从多个接口、缓存层或备用资源中先拿到一个可用结果时,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,否则它会被当成成功值。

JavaScript Promise.any 将候选 Promise 汇聚并返回第一个 fulfilled 值的结构说明图
图1:Promise.any 首个成功值的结构说明图,不是运行截图。

全部失败时用 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 转成一句“全部失败”。生产日志至少应保留来源名和错误原因;如果传入空数组,也会走失败分支,因此在构造候选列表前可以先判断是否为空,并给调用方一个更明确的业务提示。

JavaScript Promise.any 全部 rejected 后进入 AggregateError 并按输入顺序保存 errors 的结构说明图
图2:Promise.any 全失败与 AggregateError.errors 的边界说明图,不是运行截图。

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 成功后会自动停止其他请求吗?

不会。它只结束组合结果,不会取消底层操作;需要节省资源时应额外设计取消信号。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
CSS prefers-reduced-motion 怎样关闭非必要动画CSS prefers-reduced-motion 怎样关闭非必要动画
上一篇
CSS prefers-reduced-motion 怎样关闭非必要动画
JavaScript queueMicrotask 怎样安排微任务执行顺序
下一篇
JavaScript queueMicrotask 怎样安排微任务执行顺序
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    720次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    727次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    804次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    764次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    602次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码