甚麼是「Callback function」?
MDN的解釋如下:
「回呼函式(callback function)是指能藉由參數(argument)通往另一個函式的函式。它會在外部函式內調用、以完成某些事情。」
我改寫一下MDN上的範例:
最後呼叫函式 bFunc (aFunc),aFunc是bFunc的callback參數,bFunc的變數name又藉由callback傳入bFunc之中。所以我們可以理解「把A函式當成B函式的參數,透過B函式來呼叫它」,A函式就是一個Callback function。
解釋有點抽象嗎?讓我們換個場景,想想之前提過的「事件監聽」。
例如:看到紅燈,然後踩剎車!踩剎車這個動作,在「看到紅燈」這個條件滿足的時候才執行。所以我們會監聽「看到紅燈」這個事件,一旦事件觸發,就去呼叫「剎車」這個動作(函式)。這也是把「剎車」這個函式當成事件監聽的參數。
還有一個常常會用到的window.setTimeout()也是callback function的經典案例:
所以我們可以歸納出:
- 「把A函式當成B函式的參數,透過B函式來呼叫它」,A函式就是一個Callback function。
- 滿足某個條件才去執行的函式,就可以稱為Callback function。
那在甚麼時候適合使用callback function呢?我想是在「控制函式執行的時機」的情境下適合使用:
- 滿足條件,才去執行的函式。
- 控制函式執行的先後順序。
假設郭靖跟歐陽克都中了毒:
這樣的執行順序當然是先跳(‘歐陽克中毒身亡!’)的視窗,再跳(‘郭靖中毒身亡!’)。但是如果加上一個隨機生成的等待時間,那視窗的彈跳順序就不一定了。
有時是(‘郭靖中毒身亡!’)會先跳出來,有時是(‘歐陽克中毒身亡!’)會先跳出來!
如果我們想確保(‘歐陽克中毒身亡!’)比(‘郭靖中毒身亡!’)早跳出來,可以這樣寫:
這樣歐陽克就會比郭靖還要早毒發身亡了!
但是如果中毒的人越來越多,一個函式呼叫另一個函式,一層一層包下去,就變成「回呼地獄」了。
再假設另外一個情境:
「王重陽參加華山論劍,只要打敗黃藥師、洪七公、段皇爺與歐陽鋒,就會奪得『武功第一』的封號。但是不用去管王重陽與人決鬥的先後順序,只要與每個人都打過就可以。」
這時候我們可以這樣做:
Promise物件
Promise物件是ES6之後新增的物件,照字面的解釋就是「承諾」,回傳的結果只有兩種:「解決」與「拒絕」。
Promise物件長成這個樣子:
要在一個函式中使用Promise功能,只要讓它回傳一個Promise物件就行了:
Promise還提供了三種方法:
- .then():依順序串聯執行多個promise功能。
- Promise.all():直到全部函式都回覆resolve,或其中一個reject,才繼續後面功能
- Promise.race():只要其中一個函式resolve,不等待其他含式執行,直接行後續動作,
像剛剛那個「王重陽與四大高手比武」的過程就可以這樣寫:
我們在呼叫fightA()之後,用.then串接後面要執行的函式,這樣我們就可以做到依順序執行了。
來看看promise.all的情況:
Promise.all()則會等待全部的Promise函式都執行了,才會進行後面的.then函式。
然後是promise.race:
Promise.race就如同「競賽」一樣,只要有其中一個Promise函式先做到,不待其它的Promise函式完成,就直接進行.then後面的程式。但是其他的Promise函式還是會繼續執行,不會取消。