前言

Promise在程式中非常好用,是因為很多操作都需要使用到非同步的概念,而要處理非同步,除了使用callback function之外,就是會使用Promise

這篇講述我是如何理解這個概念。

今天主要講Promise的狀態跟呼叫。

Promise是一個constructor function,假如需要自己寫一個Promise時,語法如下:

1
2
3
4
const promise = new Promise((resolve, reject) => {
resolve(value);
reject(error);
});

它的參數resolve以及reject是它自己所提供的callback,不用自己額外寫,而這兩個的名稱可以自己定義像是:

1
2
3
4
const promise = new Promise((a, b) => {
a();
b();
});

效果也一樣,但是不建議這麼做。

而會設定這兩個參數,是有它的意義存在,從承諾來談吧。

Promise 狀態

可以把它想像成一個承諾,答應了某件事情,不管最後有沒有成功,都會有一個結果。

所以兩個參數的意義在於,成功跟失敗時會獲得什麼結果,所以當程式正在進行一個Promise的非同步時,如果成功就會呼叫resolve如果失敗就會呼叫reject,這裡要注意的是假設已經呼叫成功的結果了,那就回不去還沒決定的狀態,這是不可逆的,成功以及失敗只能選一個,回傳了這個結果之後,Promise就會結束。

最初的時候,是未確認的狀態,也就是pending,接著成功的話會變成Fulfilled的狀態,失敗就會是Rejected

舉例來說,小白跟小紅告白了。

前情提要,因為promise的特性一定得非同步的方式進行,代表著被告白的時候,就算遇到白馬王子,也沒辦法馬上秒答應,同樣的就算遇到非心儀對象,也不能馬上送出一張好人卡。

也就代表說,使用了promise的狀態,任何人都會一模一樣的以非同步的方式一致得到結果,像是小白也不會以同步的方式馬上被拒絕,這種藉由讓大家用統一的方式處理非同步就是promise的好處之一,而接下來小白就要開始行動了,讓我們看下去。

小白: 「我喜歡妳!」 => promise 事件開始,現在狀態是 pending。

小紅: 「let me think think.」 => 非同步開始排隊等待了,答案醞釀。

小白: 「你慢慢想!」 => 等待非同步時間結束。

— 兩天後 —

小紅: 「deserving of better people.」=> 被拒絕,現在狀態是 rejected。

小白: 「……」 => 小白 catch 到了這個 reject。

小紅: 「you are friends forever.」=> 小紅傳入 rejected 函式。

小白: 「好吧,那就還是朋友。」 => 小白知道回不去了(狀態不可逆)。

Promise 呼叫

當寫好了一個Promise,裡面已經定義好了失敗以及成功的結果後,但要取出這些結果,還需要一些方法,主要如下:

  • then()
  • catch()
  • finally()

把上面的例子寫成程式:

1
2
3
4
5
6
7
8
9
const mission = new Promise((resolve, reject) => {
setTimeout(() => {
reject("you are friends forever");
}, 200);
});

mission.catch((answer) => {
console.log(answer); //you are friends forever
});

then會捕獲成功的結果,catch則相反是失敗的,像是在這邊就可以利用catch去抓到reject裡面的函式。

使用then時會捕獲成功的結果,語法會像這樣:

1
2
3
4
promise.then(
(result) => {},
(error) => {}
);

第一個參數是成功的結果,第二個參數是失敗的,所以也可以用then去抓失敗的結果,像是這樣:

1
2
3
4
5
6
7
8
9
10
const mission = new Promise((resolve, reject) => {
setTimeout(() => {
reject("you are friends forever");
}, 200);
});

mission.then(
(result) => console.log(result),
(error) => console.log(error)
); // you are friends forever

最後一個是Finally,這個方式不會有任何參數,因為不需要,可以用這個方式來確認整個promise已經結束了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const mission = new Promise((resolve, reject) => {
setTimeout(() => {
reject("you are friends forever");
}, 200);
});

mission
.then(
(result) => console.log(result),
(error) => console.log(error)
)
.finally(() => {
console.log("小白:一切都已經結束了");
});

// you are friends forever
// 小白:一切都已經結束了

總結

執行的函式最後一定會回傳值,就算沒有寫也是回傳undefined,而在Promise來說,設計Promise物件最後的結果要不是回傳一個成功的值,不然就是失敗的值, fulfilled或是rejected,最後再複習一次,Promise的狀態只會有這三種。

  1. pending(等待中)
  2. fulfilled(已實現)
  3. rejected(已拒絕)

就算是非同步,也是有需要一個接著一個執行的狀況,其實Promise後面也是能繼續連著Promise的,就是所謂的Promises chaining,明天的文章主題,明天見。

reference

[1] 淺談 JavaScript 的 Promise
[2] MDN - Promise
[3] 你今天 Promise 了嗎?