理解 Promise.any():一次成功就行

本篇依然来自于我们的 《前端周刊》 项目!

由团队成员 嘿嘿 翻译,他的文章风格稳健而清晰,注重结构与逻辑的严谨性,善于用简洁的语言将复杂技术拆解成易于理解的知识点~

欢迎大家 进群 与他探讨,持续追踪全球前端领域的最新动态!

原文:Understanding Promise.any() - when one success is enough

在 JavaScript 中处理异步代码时,Promise 一直是我们的老朋友。如果你用过 Promise.all()Promise.race() 来协调异步操作,那你对这些模式不会陌生。但如果你只对第一个成功的结果 感兴趣,并且想要忽略失败呢?这就是 Promise.any() 登场的时机了:它会以第一个成功的 Promise 作为结果 ,并忽略所有失败的情况(除非全部失败)。

它是如何工作的

javascript 复制代码
Promise.any(iterable)
  • 它接收一个 Promise 可迭代对象。
  • 一旦有一个成功就立即返回。
  • 如果全部 失败,会抛出一个 [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError)

一个空的可迭代对象 会立即以 AggregateError 拒绝,并且其 .errors 数组为空。

日常使用场景

API 兜底(Fallback APIs)

想象一下,你要查询多个第三方接口,你只关心第一个能成功返回结果的接口

javascript 复制代码
const fetchWithCheck = (url) =>
  fetch(url)
    .then(response => {
      if (!response.ok) {
        throw new Error(`HTTP 错误: ${response.status}`);
      }
      return response;
    });

Promise.any([
  fetchWithCheck('https://mirror1.example.com/data'),
  fetchWithCheck('https://mirror2.example.com/data'),
  fetchWithCheck('https://mirror3.example.com/data')
])
  .then(response => response.json())
  .then(data => {
    console.log('从第一个可用的服务器拿到数据:', data);
  })
  .catch(error => {
    if (error instanceof AggregateError) {
      console.error('所有服务器都失败了:', error.errors);
    } else {
      console.error('意外错误:', error);
    }
  });

⚠️ 注意: fetch() 只会在网络错误(例如离线)或 CORS 策略限制时才会 reject,这些情况表现为通用的网络失败。

你也可以构建一个功能,尝试多个浏览器 API,只要有一个成功就能工作:

javascript 复制代码
const tryClipboardAPI = () =>
  navigator.clipboard.readText().then(text => `剪贴板: ${text}`);

const tryLegacyPrompt = () =>
  new Promise((resolve, reject) => {
    const text = prompt('请粘贴你的数据:');
    if (text === null) {
      reject(new Error('用户取消了输入'));
    } else {
      resolve(`输入框: ${text}`);
    }
  });

Promise.any([
  tryClipboardAPI(),
  tryLegacyPrompt()
])
  .then(result => console.log('拿到用户输入:', result))
  .catch(error => {
    if (error instanceof AggregateError) {
      console.error('没有可用的输入方式:', error.errors);
    } else {
      console.error('意外错误:', error);
    }
  });

这种模式能让功能更灵活、更友好,即使是在缺少现代 API 的老浏览器里也能用。

需要注意的坑点

  • Promise.any() 会以第一个成功的结果解决,并忽略其他的,即使后续的 Promise 失败了。
  • 如果所有 Promise 都失败 ,会抛出 AggregateError,其中包含 .errors 数组记录所有失败原因。
  • 不会中止 其他未完成的 Promise。如果需要取消,可以使用 AbortController
  • 在调用 Promise.any() 时,Promise 已经开始执行,它不会延迟执行。
  • 一个空的可迭代对象 会立即以带空 .errors 数组的 AggregateError 拒绝。

示例:处理 AggregateError

javascript 复制代码
Promise.any([
  Promise.reject(new Error('错误 A')),
  Promise.reject(new Error('错误 B'))
])
.catch(err => {
  console.log(err instanceof AggregateError); // true
  console.log(err.errors.map(e => e.message)); // ['错误 A', '错误 B']
});

与其他 Promise 方法对比

|方法|何时 resolve...|何时 reject...|说明| |-|-|-|-| |Promise.all()|✅ 全部成功时|❌ 任意失败时|适合需要全部结果 时使用。| |Promise.any()|🟢 第一个成功时|🔴 全部失败时|适合只要有一个成功就够了 。| |Promise.race()|🏁 第一个完成时(无论成功或失败)|⚠️ 同左|返回第一个完成 的结果。| |Promise.allSettled()|📦 全部完成时|🚫 永远不会 reject|返回所有结果的完整状态。|

浏览器支持情况

Promise.any() 在所有现代浏览器(Chrome 85+、Firefox 79+、Safari 14+、Edge 85+)以及 Node.js 15+ 中都受支持。对于旧环境,可以使用 [core-js](https://www.npmjs.com/package/core-js) 等 polyfill。

什么时候不该用 Promise.any()

当你只想要至少一次成功 ,并且允许部分失败时,可以使用 Promise.any()。但请避免以下场景使用:

  • 你需要所有结果 → 用 Promise.all()
  • 你想要第一个完成的结果 ,无论成功还是失败 → 用 Promise.race()
  • 你需要分别处理每个结果 → 用 Promise.allSettled() 或手动 map() + .catch()

成功优先的异步实践

Promise.any() 是一个现代且优雅的解决方案,适用于只要一次成功就够了 、并且失败是预期中的场景。无论是优化 API 请求,还是提升用户体验,它都是异步工具箱中的一大利器。

在下一个异步流程里试试它吧,尤其是当失败很可能发生时,让你的成功来自第一个抵达的来源。

相关推荐
大模型真好玩5 小时前
大模型工程面试经典(三)—如何通过微调提升Agent性能?
人工智能·面试·agent
掘金安东尼5 小时前
CSS 电梯:纯 CSS 实现的状态机与楼层导航
前端·javascript·github
张风捷特烈5 小时前
FlutterUnit 3.3.0 | 全组件、全属性、鸿蒙支持来袭
android·前端·flutter
阿亮爱学代码6 小时前
面试 八股文 经典题目 - Mysql部分(一)
面试·职场和发展·八股文·实习·sql面试
安心不心安6 小时前
React Router 6 获取路由参数
前端·javascript·react.js
在未来等你7 小时前
Kafka面试精讲 Day 4:Consumer消费者模型与消费组
大数据·分布式·面试·kafka·消息队列
fuyongliang1239 小时前
Linux shell 脚本基础 003
java·服务器·前端
lypzcgf11 小时前
Coze源码分析-工作空间-项目开发-前端源码
前端·人工智能·typescript·系统架构·开源软件·react·安全架构
yuguo.im11 小时前
Chrome DevTools Performance 是优化前端性能的瑞士军刀
前端·javascript·性能优化·chrome devtools