有關瀏覽器Event loop對於javascript的影響
首先,參考的技術影片網址如下:
https://www.youtube.com/watch?v=8aGhZQkoFbQ&t=1605s
在講到關於事件循環(event loop)前,必須先行了解到幾個需要知道的技術名詞。
何謂單線程語言(single threaded):
Javascript是屬於一種單線程的語言,因此在執行程式碼的時候會一次只執行一段程式打的片段,而每段程式碼會被推入到所謂的堆疊(stack)中去執行。
何謂堆疊(stack):
Javacript中的執行堆疊(call stack)會記錄程式執行到哪個階段。若是呼叫了函式(Function)的話會添加該Function到堆疊的最上方。當Function執行完畢後,該Function便會從最上方抽離。以下面的程式碼為例:
// 1
function multiply(a, b) {
return a * b
}
// 2
function square(n) {
return multiply(n, n)
}
// 3
function printSquare(n) {
let squared = square(n)
console.log(squared)
}
// 4
printSquare(4)
執行Function的時候,stack為全域環境的程式。接這printSquare會先被呼叫後進入堆疊的最上方,然後再呼叫了square(),再將其進入stack最上方。而相同的multiply()被呼叫了進來,也會跑到stack最上方。因此變成如下:
| multiply(n,n) |
| square(n) |
| printSquare(4) |
| main() |
隨後執行完後便一一的抽離堆疊。(參考影片的5:27位置)
非同步處理(Async)
由上面的敘述看到,在call stack中會一段一段的處理程式碼,若是一段程式碼執行過久的話則會造成阻塞(blocking)。這個過程叫同步處理。而非同步處理的時在這個程式執行時,利用別的方式去執行其他的程式碼片段,可以將減少blocking。
那Javascript又是個單線程的語言,要一步一步執行程式碼片段,如何去做到非同步處理?此時就要想到Javascript是在瀏覽器(Browser)下執行的,因此會有個WebAPI提供。將執行較慢的程式先丟入到WebAPI中執行,主程式則是繼續執行其他的工作,因此才造就了看似Javascript可以執行Async的感覺。其範例如下:
console.log('hi')
setTimeout(function () {
console.log('there')
}, 5000)
console.log('JSConfEU')
一開始先正常照順序執行後如下:
| console.log(‘hi’) |
| main() |
| setTimeout() |
然而在setTimeout()有設立5秒,結果執行堆疊的部分消失於最上層,反而先行執行最後的console.log。
| console.log(‘hi’) |
| console.log('JSConfEU') |
| main() |
結果帶執行完畢之後,最後才出現setTimeout()的結果。
(以上執行跟程式碼請參考影片11:35的位置)
這個時候的問題就在於瀏覽器裡面的Event loop
何謂Event loop
先前提到Browser有提供所謂的WebAPI的工具,而上述程式碼的setTimeout()便是其中的一個。因此當setTimeout()在執行裡面的Function後,便會從堆疊中移除,並移動到WebAPI裡面執行倒數的功能。然後再推到瀏覽去的工作佇列(task queue),等待進一步的指示。也因為這樣此時Javascript也先同時進行另一個程式。
當stack清空完之後,此時event loop會將task queue的項目依序放入到stack去執行最後的動作。因此上述的程式碼才會print出的順序為:
Hi ⇒ JSConfEU ⇒ there
(圖形概念請參考影片12:50位置)
結語:
在講了這麼一大段的名詞解釋後,最後才將event loop講解了一小段。但是其實這是一個整個脈絡,不先知道因,後面的果就會不曉得如何產生,因此整個理解後,這樣Event loop的扮演的角色才會很清楚了解,其實就是整個執行順序上的問題。

