0%

JS特訓-DAY40-ES6 團戰關卡 Promise (1)

前言

介紹 ES6 的新語法 Promise

介紹 Promise 之前,先更深入的了解一下使用 callback 會遇到什麼問題。


callback 的問題

這是個關於信用卡扣款的例子。

今天有一個電商網站,為了想要製作一個慾望清單來增加客戶的購買率。為了製作這個慾望清單,在 survey 之後,決定套用一

個專門用來統計資料的函式庫。


這個函式庫需要我們去呼叫一個 叫做 analyze 的 API 來做資料的統計。analyze 是一個非同步的函式,總共要帶入兩個參數:

要統計的資料 data 以及 非同步執行完之後的操作 callback


因此套用第三方函式庫的 API 後,程式會變成這樣:

analyze({}, chargeMoney.bind(null, 100));

function chargeMoney(money) {
  console.log('charged ' + money);
}

// charged 100
// charged 100

一切看起來正常,結果新的版本上線之後,發現有的使用者竟然回報被扣款了兩次!?

事情大條了,但是你百思不得其解,畢竟在你程式中使用到扣款的地方只有單單這一行,而且你還曾為了寫出這段簡潔的程式而

沾沾自喜過:

analyze({}, chargeMoney.bind(null, 100));

你很直覺的就發現可能是這個第三方函式庫有問題,追了一下發現果然:

function analyze(data, callback) {
  // analyze data
  callback();
  // some more codes
  callback();
}

這個第三方函式庫的 analyze API 竟然有 Bug,他呼叫了你的 callback 兩次,而你帶入的 callback 就偏偏是事關重要的扣

款功能。


Promise

因此 ES6 新增了一個新語法:Promise

Promise 顧名思義就是承諾,如果承諾兌現,就繼續做計畫好的下一件事;如果承諾被打破了,就不繼續做下一件事。

語法概述

Promise 的精隨就是要用來解決可靠性問題。先來看看它的用法:

var defer = new Promise(function(resolve, reject) {
        // if success, resolve()
        // if fail, reject()
  })
  .then(laterOn)
  .catch(printError);

我們可以使用 new Promise 來創建一個新的 PromisePromise 可以帶入一個函式,而這個函式又會被傳入兩個參數:

resolve & reject


如果我們的 Promise 成功完成的話,就可以呼叫 resolve() 來回傳 Promise,接著我們就可以用 then 來接續這個

非同步執行完後要做的動作。


如果我們的 Promise 失敗的話,就可以呼叫 reject() 來回傳 失敗原因,接著我們就可以用 catch 來接住錯誤。

Promise 被解析成 resolvereject 之後,其值就無法再被改變。


回到範例

接著讓我們回到信用卡的範例,但這次,我們要試試看 Promise 能不能真的解決可靠性的問題。

先來看我們的第三方函式庫,假設他們是使用 Promise 的語法犯了錯,很不小心的執行了 resolve 兩次:

function analyze(data) {
  return new Promise(function(resolve, reject) {
  // something else
    // analyze data
    resolve();
    // some more codes
    resolve();
  })
}

而我們的程式使用 Promise 改成這樣:

analyze({})
  .then(chargeMoney.bind(null, 100));

function chargeMoney(money) {
  console.log('charged ' + money);
}

// charged 100

很神奇的,竟然換成 Promise 之後就沒有被重複扣款了!?


這是因為我們前面所說的:當 Promise 被解析成 resolvereject 之後,其值就無法再被改變,而就算你呼叫 resolve

次,第二個 resolve 也不會再被解析。


更重要的是,我們現在不在需要傳入 callbackanalyze ,而是換成 analyze 回傳的是一個 Promise,等到 analyze 完成

了自己的非同步動作,才會由我們執行 chargeMoney 函式,而我們也並沒有 chargeMoney 兩次,所以當然只會扣一次款而已。


Promise 特點

因此我們可以看到 Promise 的兩大重點:

  • 可靠

我們可以信任 Promise 回傳的東西,這回傳值一旦回傳就無法被更改。

  • 控制回歸

我們將執行 callback 的控制權拿回來了,現在如何使用 callback 由我們自己操控。


結論

在這篇中,我們探討了 callback 的 特性 與 問題:

  • callback 特性:控制的反轉

因此造成了以下的問題

  • callback 的問題:可靠性不足

為了解決這個問題,ES6 新增了新語法 Promise


因為 Promise是為了解決上述的兩大問題所以他當然有以下兩個特點:

  • 可靠

Promise 回來的東西是可信任的,一旦回傳就無法被更改。

  • 控制回歸

將執行 callback 的控制權回歸自己的程式。


參考