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

留言

目錄

  1. 使用情境
  2. 資料來源

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

本文同步發表於 iT 邦幫忙:JavaScript 之旅 (27):Promise.any() & AggregateError

「JavaScript 之旅」系列文章發文於:

之前有介紹 ES2020 (ES11) 提供的 Promise.allSettled(),它不會發生短路,也就是都會等所有傳入的 Promise settled (即 fulfilled 或 rejected ),而本篇介紹的 Promise.any() 則是會因其中一個傳入的 Promise fulfilled 而發生短路。

例如:在 Promise.any() 傳入 3 的 Promise,只有第一個會立即 rejected,其餘的都會立即 fulfilled:

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

可以看到最後回傳的 Promise 會 fulfilled,因為 Promise.any() 只要其中一個 Promise fulfilled 就會發生短路,即會立即回傳該 Promise fulfilled:

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

若所有傳入的 Promise 都 rejected,則會以 AggregateError rejected,並會保留所有 rejection reasons (即下面範例中的 error.errors ):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 物件:

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

使用情境

Promise.any() 很適合用在一次處理多個非同步,並且抓出第一個 fulfilled 的 Promise,只有當全部都 rejected 才進行錯誤處理。

例如:同時發多個 request,看哪一個 endpoint 回應最快,然後把該 endpoint 紀錄下來。而且只有當所有 request 都發失敗時,才會進行錯誤處理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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()

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

資料來源

分享:

討論區