前言
介紹 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 來創建一個新的 Promise。Promise 可以帶入一個函式,而這個函式又會被傳入兩個參數:
resolve & reject。
如果我們的 Promise 成功完成的話,就可以呼叫 resolve() 來回傳 Promise,接著我們就可以用 then 來接續這個
非同步執行完後要做的動作。
如果我們的 Promise 失敗的話,就可以呼叫 reject() 來回傳 失敗原因,接著我們就可以用 catch 來接住錯誤。
當 Promise 被解析成 resolve 或 reject 之後,其值就無法再被改變。
回到範例
接著讓我們回到信用卡的範例,但這次,我們要試試看 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 被解析成 resolve 或 reject 之後,其值就無法再被改變,而就算你呼叫 resolve 兩
次,第二個 resolve 也不會再被解析。
更重要的是,我們現在不在需要傳入 callback 給 analyze ,而是換成 analyze 回傳的是一個 Promise,等到 analyze 完成
了自己的非同步動作,才會由我們執行 chargeMoney 函式,而我們也並沒有 chargeMoney 兩次,所以當然只會扣一次款而已。
Promise 特點
因此我們可以看到 Promise 的兩大重點:
- 可靠
我們可以信任
Promise回傳的東西,這回傳值一旦回傳就無法被更改。
- 控制回歸
我們將執行
callback的控制權拿回來了,現在如何使用callback由我們自己操控。
結論
在這篇中,我們探討了 callback 的 特性 與 問題:
callback特性:控制的反轉
因此造成了以下的問題
callback的問題:可靠性不足
為了解決這個問題,ES6 新增了新語法
Promise。
因為 Promise是為了解決上述的兩大問題所以他當然有以下兩個特點:
- 可靠
Promise回來的東西是可信任的,一旦回傳就無法被更改。
- 控制回歸
將執行
callback的控制權回歸自己的程式。