前言

前幾天講的Promise的 then()、catch()、finally()也是Promise的 methods,從 MDN 的定義上會把這三種 methods 稱之為Instance methods,而今天要講的是Static methods,中文叫做靜態方法,大致上可以分成六種,這些的方法都是為了更好的使用Promise而被發明出來,可能用不到但懂了沒壞處。

哪六種:

  • Promise.all()
  • Promise.allSettled()
  • Promise.any()
  • Promise.race()
  • Promise.resolve()
  • Promise.reject()

會嘗試用好理解的方式介紹,let’s go。

Promise.all()

執行很多的Promise會用到,簡單來說,全部都達成才會成功,不然就會失敗。
舉一個例子,小白願意去找工作,但他有著前提條件,只要他擁有了一台車,然後有了房子,還擁有 100 萬的存款,他就會去找工作。

1
2
3
4
5
6
7
8
Promise.all([
new Promise((resolve) => setTimeout(() => resolve("獲得車"), 100)),
new Promise((resolve) => setTimeout(() => resolve("獲得房子"), 200)),
new Promise((resolve) => setTimeout(() => resolve("獲得100萬"), 300)),
new Promise((resolve) => setTimeout(() => resolve("=> 好! 去工作"), 400)),
]).then(console.log);

// [ '獲得車', '獲得房子', '獲得100萬', '=> 好! 去工作' ]

會等到全部的結果都成功,才會全部都 resolve, 會發現說它回傳的會是一個 array,這個 array 裝的東西就是所有的結果。

只要有一個失敗,就直接失敗,就像是只要有一個前提條件沒達成,小白就沒辦法去找工作。

1
2
3
4
5
6
7
8
9
10
11
12
Promise.all([
new Promise((resolve) => setTimeout(() => resolve("獲得車"), 100)),
new Promise((resolve) => setTimeout(() => resolve("獲得房子"), 200)),
new Promise((resolve, reject) =>
setTimeout(() => reject(new Error("沒有一百萬,沒人要給你")), 300)
),
new Promise((resolve) => setTimeout(() => resolve("=> 好! 去工作"), 400)),
])
.then(console.log)
.catch(console.log);

// Error: 沒有一百萬,沒人要給你

其中有一個被reject就會導致全部整個Promise.all都被reject,最後的結果就是reject裡面寫好的Error訊息。

Promise.allSettled()

情境是使用在都每種Promise都想知道結果的時候。

代表說成功或是失敗的結果都會被記錄下來,這兩種都會被裝在一個陣列裡面。

成功

1
{status:"fulfilled", value:成功的訊息}

失敗

1
{status:"rejected", reason:失敗的訊息}

繼續上方的例子,小白做好準備要出發去找工作,他的策略是履歷海,什麼都投,投完後開心地坐在家中等消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Promise.allSettled([
// 找工作是一個包著promise的函式,裡面就會放失敗跟成功的訊息

找工作("第一間公司", 100),
找工作("第二間公司", 200),
找工作("第三間公司", 300),
])
.then((value) => console.log(value));
.catch((err) => console.log(err));

// 結果=>
[
{ status: 'fulfilled', value: '第一間公司:發來面試請求!' },
{ status: 'rejected', reason: '第二間公司,無聲卡' },
{ status: 'fulfilled', value: '第三間公司:發來面試請求!' },

]

其中有一個被reject,也會把其他結果通通跑完,跑完之後會能看到所有的結果,無論結果是如何,都會全部都被settle,所以叫做allSettled

Promise.any()

假如成功就馬上成功,直到全部都失敗。

而在全部都失敗的狀態下,會回傳一個叫做AggregateError的物件裡面,把失敗的訊息都放進去。

小白出發前往面試,他只要有上就好,成功了就不會繼續下一間。

1
2
3
4
5
6
7
8
9
Promise.any([
new Promise((resolve, reject) =>
setTimeout(() => reject(new Error("失敗,下一間")), 100)
),
new Promise((resolve, reject) =>
setTimeout(() => resolve("成功找到工作"), 200)
),
new Promise((resolve, reject) => setTimeout(() => resolve("回家睡覺"), 300)),
]).then(console.log); // 成功找到工作

假如完全都沒有任何公司是面試成功的話:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Promise.any([
new Promise((resolve, reject) =>
setTimeout(() => reject(new Error("失敗,下一間")), 100)
),
new Promise((resolve, reject) =>
setTimeout(() => reject(new Error("失敗,下一間")), 200)
),
new Promise((resolve, reject) =>
setTimeout(() => reject(new Error("失敗,下一間")), 300)
),
])
.then(console.log)
.catch((error) => {
console.log(error.constructor.name, error.errors);
});

// 會出現:
AggregateError [
Error: 失敗,下一間
Error: 失敗,下一間
Error: 失敗,下一間
]

Promise.race()

Promise.any有點像,當一個promise有結果,就回傳跟結束。

剛剛提到小白找到了工作,他很開心想要慶祝,所以打算去吃一間豪華的餐廳,他還沒想要要吃什麼,抱著不想找太久的心手舞足蹈的前往。

1
2
3
4
5
6
7
8
9
10
11
Promise.race([
new Promise((resolve, reject) => setTimeout(() => resolve("吃牛排"), 200)),
new Promise((resolve, reject) => setTimeout(() => resolve("吃拉麵"), 300)),
new Promise((resolve, reject) => setTimeout(() => resolve("吃火鍋"), 400)),
])
.then(console.log)
.catch((error) => {
console.log(error);
});

// 吃牛排

小白看到了牛排,然後裡面就有位子不用排隊,二話不說就直接開吃了。

到這邊跟Promise.any幾乎一模一樣,有了一個成功,其他都就不會去看直接結束。

但是要是第一間要去的不是牛排店,而是人很多的燒賣店呢?讓我們看下去。

1
2
3
4
5
6
7
8
9
10
11
12
13
Promise.race([
new Promise((resolve, reject) =>
setTimeout(() => reject(new Error("人太多,不吃了")), 100)
),
new Promise((resolve, reject) => setTimeout(() => resolve("吃牛排"), 200)),
new Promise((resolve, reject) => setTimeout(() => resolve("吃拉麵"), 300)),
new Promise((resolve, reject) => setTimeout(() => resolve("吃火鍋"), 400)),
])
.then(console.log)
.catch((error) => {
console.log(error);
});
// Error: 人太多,不吃了

小白第一間到了燒賣店,看到了那人山人海的群眾,內心湧入一陣倒胃,突然就沒有吃飯的慾望了,於是就直接回家結束了這回合。

這就是Promise.race的特性,不管是成功還是失敗,Promise.race都會被解決。

Promise.race() 和 Promise.any() 比一比

來複習一下這兩者的差別:

Promise.race:
不管是成功還是失敗,都會直接完成。

Promise.any:
當成功了,或是全部都失敗,才會完成。

兩個都會有拒絕的狀況,Promise.race的拒絕狀況是因為碰到了第一個Promise拒絕後就馬上拒絕,而Promise.any是全部都被拒絕後,回傳一個,AggregateError

要如何使用它們兩個,要依照情境而定,可以知道的是他們兩個很相似但是依舊是不同的東西。

Promise.resolve()

我的理解是設定Promise成功後的訊息。

1
2
3
4
5
const promise = Promise.resolve(1);

promise.then((value) => {
console.log(value);
}); //1

Promise.reject()

reject就是Promise失敗後的訊息,所以要用 catch()去抓。

1
2
3
4
5
const promise = Promise.reject(1);

promise.catch((value) => {
console.log(value);
});

小結

每一種方法都有它適合的情境,在使用promise可以試著用用看這些方法~說不定會發現方便又好用,而我個人體感跟爬文看到來說,Promise.all這個方法是實際上會使用最多的,所以可以考慮先從這個開始下手認識,那麼今天就是這些,謝謝明天見。

reference

[1] MDN - Promise
[2] What is the difference between Promise.any() and Promise.race()