Javascript: Callback, Promise, Async/Await

What is Callback?

Javascript 是一個 Asynchronous (非同步) 的語言。有 Asynchronous 當然也有 Synchronous, 它們之間的分別是:

Synchronous 是一個 function 接一個 function 來執行, 當前面的 function 未 return 後面的是不會執行的。

Asynchronous 則是不會等前面的 function return 而直接去執行下一個 function。 Javascript 就是這一種。

那麼如果 Javascript 想好像 Sync 一樣讓 functions 按著次序一個一個來執行, 應該怎樣?

這就是 Callback 登場的時候了。 Callback 的意思就像跟別人講電話說當你忙完你的事情請回我電話。在 Javascript如何實現呢?

simple callback example

這段code展示了一個簡單的 callback 的用法。我們希望先執行了 function a 再執行 function b 所以我們把 b 作為 a 的 argument 傳進去。但事情並不是這麼簡單,如果 b是一個需要等待的function。跟據JS的Asyn特性,它是不會等待的,因此之後的function會優先執行。

function c 比 function b 先執行

所以需要更多的callback function才能實現順序執行。

但是當程式越來越複雜,將需要更多的callback functions。這樣會產生一個問題 — Callback Hell !!

https://adrianalonso.es/wp-content/uploads/2019/01/streetcallback.png

雖然在功能上,它可以滿足我們的要求,但是在閱讀性和維護性上則是大災難。

Promise!

它是ES6新增的功能,Promise並不為了解決 callback hell 而創造出來,而是提供另一個方法去解決 Javascript Async 的問題。當一個 Async 完成了的時候就會產生一個 Promise,這個 Promise會 return「成功」或者「失敗」給它的 Handler。而 return 的形式令 Async function 和 Sync function 更相似。

Promise 有三種 states:

Pending: operation 剛剛開始和正在執行中。

Fulfilled: operation 成功。

Rejected: operation 失敗。

How does Promise work?

Promise flow chart from MDN web docs

.then(function(){…})是當Promise fulfill的時候出來接應的handler。

.catch(function(){…})是當Promise reject的時候出來接應的handler。

無論 .then() / .catch()都是 return Promise Object的,因此是可以不斷地 .then() / .catch()的。

這樣就創造了一個Promise Object,當成功時就使用resolve(…),而失敗時就使用reject(…)。

上面的例子展示了promise不同的用法和情況。首先我們有一個 function ‘output’ return 一個 promise object。內容很簡單就是等一秒之後如果有value就成功,沒有就失敗。Test1,傳一段string去output,它順利地使用resolve function和call了進入了then()。Test2,顯示如果失敗的情況和顯示有兩種寫法。

Test3,顯示如果我們在then(…)中return一個promise,我們是可以直接再使用then()去接的。

到了這裡,我們發現如果程式越趨複雜,promise hell 也是會出現的。為了有更好的閱讀性和維護性,async/await 出現了。

Async/Await

它們兩兄弟是 Syntactic Sugar,其令到 promise 更容易理解和使用。

Syntactic Sugar:有些 programming syntax 就像黑咖啡一般不是人人都容易入口,加一些糖 (Syntactic Sugar)令到咖啡更容易入口,而且糖是不會改變咖啡的結構的。

Async function 的工作只有一樣就是自動 return promise object。

Await 只可以在 async function 內使用,它的工作是暫停 async function 內的其他function執行直到當下的 function 完成處理它的 promise 和 return 其結果。

以下我們會用例子去比較 promise 和 async/await 的寫法有甚麼不同。

對於一開始的 process() 來說,它加不加 async 其實分別不大,它都會return promise object。而對於 promise 和 async/await 的閱讀難度也不大分別。

那麼以下是一另個例子:

Using Promise
Using Async/await

由此可見,當程式越來越複雜,可見 Async/Await 的寫法是更清楚的。

Conclusion

Callback, Promise, Async/Await 在寫法上是不同但它們的本質是一樣的,都為了在 Javascript 實現 Sync 的效果。

--

--

A Programmer, Data Engineer

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store