這其實不是難懂的概念,但卻是非同步程式設計中最基礎的螺絲釘,我自己在學習這JS非同步領域這系列的順序是這樣排的:
Callback => Promise => Async/Await
確保自己了解之後,再往下一個階段邁進,對於認知非同步反而會顯得更加輕鬆,不然容易變成拆東牆補西牆。
這個概念是我從huli的JavaScript 中的同步與非同步(上):先成為 callback 大師吧!學習到的,也是這篇讓我意識到callback
的重要性,推薦可以去看。那麼就開始進入今天的主題。
Callback Funtion
定義學習一個新的名詞術語,想知道它究竟是什麼,有很多方式,Callback
來說的話我覺得可以看MDN文檔的定義,寫的蠻好理解:
A callback function is a function passed into another function as an argument
中文來說的話就是,當一個函數,作為參數傳遞給另一個函數,就是callback
。
舉例來說:
小白、小紅、小黃三個人在工作,可以這樣寫。
whiteWork();
redWork();
yellowWork();
雖然程式會確實的從上到下執行,所以看起來沒有問題,但卻不能保證執行的順序,但今天如果使用Callback
就可以,像是我想要小白做完後小紅再開始工作,那我就可以把小紅放到小白的Callback
裡面。
whiteWork(function () {
redWork();
});
yellowWork();
這樣子的好處,是讓程式的某個函數執行完,再接著執行其他的函式。
那換來看看MDN的例子:
function greeting(name) {
alert(`Hello, ${name}`);
}
function processUserInput(callback) {
const name = prompt("Please enter your name.");
callback(name);
}
processUserInput(greeting);
這段程式執行後會像是這個樣子。
跳出一個視窗詢問名字。
輸入名字(vic),按確定
跳出"Hello,vic"
正常沒有使用Callback
的版本如下。
function greeting(name) {
alert(`Hello, ${name}`);
}
function processUserInput() {
const name = prompt("Please enter your name.");
}
processUserInput();
greeting();
但會發現跟上面不一樣,輸入名字後,卻找不到名字。
這個就是Callback
很重要的地方,這種呼叫後順序不一致的狀態,我想要哪個先呼叫,有時候不是先放前面就沒事了,像是在這邊我雖然把processUserInput()
放前面,但不代表後面的greeting()
就會乖乖的等上面的問題問完才顯示,在JavaScript
的世界裡面,會越快完成的事情會先做完,有一件要等待的事情,一件馬上顯示出來的事情時,不管排序都會先去做那馬上可以完成的,那要是有很多件不確定時間的事情,就會完全無法確認順序。
但是有了Callback
就不一樣,可以藉由某個做完再呼叫的機制,確保順序,在這種單執行緒的環境下,JavaScript
沒辦法像是其他程式語言可以直接多工去同時做很多事情,所以需要有一種「被呼叫才做事」的功能,這也是我理解為什麼需要一個函數,作為參數傳遞給另一個函數的原因。
在其他地方有看到一個用工人來解釋Callback Funtion
很好懂的比喻,在JS20min Day — 18 關於回呼生活化 (Callback)看到的。
假如小白跟小黃都是工人。
小白是一個正在睡覺的工人,被叫時才會起來工作。
而小黃是勤奮型工人,他會去工作,也會去叫小白起來工作。
function whiteWork() {
console.log("被小黃叫,來去工作");
}
function yellowWork(call) {
console.log("先工作,叫小白");
call();
}
yellowWork(whiteWork);
這樣的執行順序會是:
1.工作,叫小白
2.被小黃叫,來去工作
就是當一個函數,作為參數傳遞給另一個函數,在這邊小白會作為一個參數去傳遞給小黃這個函數,而本身小白也是一個函數。
假如事情一定要一個做完才接著下一個,後面的Callback
會需要使用到前面Callback
的結果,也就是必須在Callback
中再Callback
,那整體的架構就勢必沒辦法是平行的,會很複雜,像是這樣。
出處:https://github.com/explooosion/emoji-comment-collection/issues/6
就這是多層環環相扣後所產生的波動拳,不只看起來很是複雜,維護起來時也會很麻煩,這也是為什麼後面還需要使用到promise
的原因,關於這部分後續幾天會提到,那今天的介紹就到這邊。
下一篇會講述在JavaScript
中的非同步程式設計是怎麼一回事,明天見~
[1] MDN - Callback function
[2] W3Schools - JavaScript Callbacks
[3] The Modern JavaScript Tutorial - Introduction: callbacks
[4] You Don't Know JS - Callbacks
[5] 你懂 JavaScript 嗎?#23 Callback
[6] 重新認識 JavaScript: Day 18 Callback Function 與 IIFE