7

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

 3 years ago
source link: https://titangene.github.io/article/javascript-promise-any-aggregateerror.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
JavaScript 之旅 (27):Promise.any() & AggregateError
javascript.jpg

本篇介紹 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'),
]);

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK