iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
0
自我挑戰組

玩轉 React 從0到1系列 第 10

【Day 10】關於ES6 的 Promise

  • 分享至 

  • xImage
  •  

前言

什麼是 Promise ?

Promise 就是承諾,承諾過一段時間會給你個結果(承諾來解救 Callback Hell 的)。

什麼是 Callback 呢? 如果只有一個 Callback 很好用,那就是執行完成後的下一件事,但是...
(經歷過的就知道,下面的代碼讓我想關掉電腦) 猜猜看現在執行到哪裡了呢? XD

// Callback Hell
a(function(resultA) {
    b(function(resultB) {
        c(function(resultC) {
            d(function(resultD) {
                console.log(resultD);
            })
        })
    })
})

Callback通常會伴隨著幾種問題,包含:
1.多重的 Callback 導致 Callback Hell,也導致程式碼不直觀
2.Callback 存在著 控制權移轉 (Inversion of Control) 的問題,意思就是當一個函數移轉到另外一個函數時,有時候會出現非預期的狀況。
3.如果不寫 Error Callback 處理函數,異常就會抓不到了

註:Callback Hell 在大部分的程式語言比較少會遇到這樣的問題,主要是因為他們以同步的機制為主,但在大量使用異步的 Javascript 中我們就需要解決這項問題。


那 Promise 怎麼解決些問題?

Promise 的經典在於 狀態 ,用維護狀態、傳遞狀態的方式使得回調函數能夠即時調用,也使得異步函數可以同步化。

Promise

Promise 是一個構造函數,用來生成 Promise 實例

Promise 共有三種狀態,包含: pending(進行中)、fulfilled(已成功)、rejected(已失敗),而 Promise 的狀態是來自於異步操作,只有異步操作的結果可以決定是哪一種狀態,其他操作無法去更動這個狀態,在狀態改變後就不會在變了,有可能是從 pending 到 fulfilled (事件成功) 或是 從 pending 到 rejected (事件失敗),也就在這個時候狀態就終止了。

Promise 有兩個參數:

  • resolve : 當 Promise 狀態從 從 pending 到 fulfilled 時調用,將異步的結果作為參數傳遞出去
  • reject : 當 Promise 狀態從 從 pending 到 rejected 時調用,將異步的結果作為參數傳遞出去
let state = 1;

function step1 (resolve, reject) {
    console.log('Do the laundry');
    if (state == 1) {
        resolve('Do the laundry - Finish');
    } else {
        reject('Do the taundry - Fail');
    }
}

function step2 (resolve, reject) {
    console.log('Dry the clothes');
    state = 2;
    if (state == 1) {
        resolve('Dry the clothes - Finish');
    } else {
        reject('Dry the clothes - Fail');
    }
}

function afterStep2Pass(resolve, reject) {
    resolve('pass');
}

function stepCatch (resolve, reject) {
  console.log('The machine is broken');
  if (state != 1) {
    resolve('Fix the machine');
  }
}

new Promise(step1).then(val => {
    console.log(val);
    return new Promise(step2)
}).then(val => {
    return new Promise(afterStep2Pass); // 因為 step2 reject,這一段會被跳過
}).catch(val => {
    console.log(val);
    return new Promise(stepCatch);
}).then(val => {
    console.log(val);
    return val;
}).finally(() => {
    console.log('done');
})
// Do the laundry, Do the laundry - Finish, Dry the clothes, Dry the clothes - Fail, The machine is broken, Fix the machine, done

上面的例子是以清潔衣服為例子,要完成洗衣服這項動作需要經過:洗衣服、烘乾衣服,要保證上一步完成,才能進行到下一步,如果中間出問題了,像是機器壞掉就會送 catch,當然也因此 step2 後面的 then 就直接被跳過了。如果以ES6之前可能要兩層 Callback,上方是改寫為 Promise 的方式。

執行順序是 step1->step2-(因改state,reject前往 catch)->stepCatch->finally

Promise.prototype.then()

then 方法是作為 Promise 改變狀態後的 Callback,onFulfilled[, onRejected],then 第一個參數是 fulfilled 狀態的 Callback,第二個參數是 rejected 狀態的 Callback

var p1 = new Promise( (resolve, reject) => {
  resolve('Success!');
  // or
  // reject ("Error!");
} );

p1.then( value => {
  console.log(value); // Success!
}, reason => {
  console.log(reason); // Error!
} );

Promise.prototype.catch()

catch 方法是 then(null, rejection) 或 then(undefined, rejection)的別稱,用於 Promise 發生錯誤時的 allback。

Promise.prototype.finally()

finally 方法用於不管 Promise 最後的狀態如何,這操作都會執行


Promise.all()

多個 Promise 行為同時執行,全部完成後統一回傳

const p = Promise.all([p1, p2, p3]);

如果 p1, p2, p3 狀態都變成 fulfilled,p 的狀態才會是 fulfilled,這時候返回 [p1, p2, p3]的陣列結果給 p。

Promise.race()

多個 Promise 同時執行,但僅回傳第一個完成的

執行方式跟 Promise.all() 一樣,唯一不同的是執行完後它只返回單一結果,為第一個運行完成的,以上方Promise.all 的例子也就是 p1。

Promise 缺點

Promise 在建立後就會立刻執行,無法(中途)取消 Promise,如果不設置 Callback,Promise 內部拋錯就不會反應到外部。如果處於 pending 狀態時,無法知道現在到哪個階段了。

結論

  • 介紹了 Callback 問題
  • 介紹了 Promise

/images/emoticon/emoticon11.gif

參考

Promise到底解决了哪些问题?


上一篇
【Day 9】關於ES6 的 同步與異步
下一篇
【Day 11】穿越 ES6 邁向 ES7 的 async/await
系列文
玩轉 React 從0到130
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言