JavaScript 之旅 (27):Promise.any() & AggregateError

本篇介绍 ES2021 (ES12) 提供的 Promise.any()AggregateError

之前有介绍 ES2020 (ES11) 提供的 Promise.allSettled(),它不会发生短路,也就是都会等所有传入的 Promise settled (即 fulfilled 或 rejected ),而本篇介绍的 Promise.any() 则是会因其中一个传入的 Promise fulfilled 而发生短路。

例如:在 Promise.any() 传入 3 的 Promise,只有第一个会立即 rejected,其余的都会立即 fulfilled:

let promise = Promise.any([
  Promise.reject('Oops 1'),
  Promise.resolve('OK 1'),
  Promise.resolve('OK 2')
]);

可以看到最後回传的 Promise 会 fulfilled,因为 Promise.any() 只要其中一个 Promise fulfilled 就会发生短路,即会立即回传该 Promise fulfilled:

console.log(promise);
// Promise {<fulfilled>: "OK 1"}

若所有传入的 Promise 都 rejected,则会以 AggregateError rejected,并会保留所有 rejection reasons (即下面范例中的 error.errors ):

Promise.any([
  Promise.reject('Oops 1'),
  Promise.reject('Oops 2'),
  Promise.reject('Oops 3')
])
.catch(error => {
  console.log(error instanceof AggregateError);
  console.log(error.errors);
  console.log(error.message);
  console.log(error.stack);
});

// true
// ["Oops 1", "Oops 2", "Oops 3"]
// All promises were rejected
// AggregateError: All promises were rejected

另外,你也可以自行建立新的 AggregateError 物件:

// 语法:AggregateError(errors, message)
new AggregateError([errorA, errorB, errorC], 'error message');

使用情境

Promise.any() 很适合用在一次处理多个非同步,并且抓出第一个 fulfilled 的 Promise,只有当全部都 rejected 才进行错误处理。

例如:同时发多个 request,看哪一个 endpoint 回应最快,然後把该 endpoint 纪录下来。而且只有当所有 request 都发失败时,才会进行错误处理:

let Base_URL = 'https://jsonplaceholder.typicode.com';

let promises = [
  fetch(`${Base_URL}/posts/1`).then(() => 'post'),
  fetch(`${Base_URL}/todos/1`).then(() => 'todo'),
  fetch(`${Base_URL}/comments/1`).then(() => 'comment')
];

try {
  const first = await Promise.any(promises);
  console.log(first);

  // 纪录 log...
  // Logger.log(first);
} catch (error) {
  console.log(error.errors);

  // 错误处理...
}

另一个适合的情境是你想动态 import 一个模组,但有两个来源可以 import,但你只需 import 最快的那一个即可,此时也很适合用 Promise.any()

const lodash = await Promise.any([
  import('https://primary.example.com/lodash'),
  import('https://secondary.example.com/lodash'),
]);

资料来源


<<:  NestJs 延伸篇 - Federation 实作

>>:  (Day 29) DevOps Challenges

Day23:进入聊天室状态判断

在书写逻辑之前,先厘清程序要达成的需求是什麽? 页面上会有两个组件,一个是登入用,另一个则是用来显示...

资讯安全管理制度导入范围与验证范围

导入范围与验证范围差异比较如下: 范围 导入 验证 订定1~4阶程序书 ○ ○ 落实资讯资产资讯蒐集...

Day 18 -SQL 函数 SUM()!

SUM() 函数用来计算一数值栏位的总合。用来算金额等数字类型的都很好用~ SUM() 语法 (SQ...

【Day 30】第12届iT邦帮忙铁人赛 - 完赛笔记

最近依旧忙录,但工作的需要,我还是需要了解新的技术,努力排出时间用在技术研读上,评估一些技术引进的议...

Day 29 | SQLite资料库(四)

查询资料 query()方法 //查询资料 var number = "" va...