[學習筆記] JavaScript 的 Event Loop, Stack, Queue

I caught a code
I Caught a Code
Published in
6 min readJan 7, 2021

--

試著理解概念,並嘗試自己講一遍

此篇為觀看 [What the heck is the event loop anyway? | Philip Roberts | JSConf EU]學習筆記

— -

## 前言

學習 JavaScript 至今有三個月時間,開始注意到 JavaScript 執行程式碼的規律:主程式由上而下一行一行執行,遇到要執行的函式時再回頭呼叫函式內容,執行完函式內容再返回剛剛停下來的地方,繼續往下執行主程式直到結束。

JavaScript 是一種 單執行緒 (single threaded) 程式語言,也就是「一次只能做一件事,做完一件事再接著做下一件事」。這樣看來效率似乎比較差,但 JavaScript 在瀏覽器中,透過區分同步與非同步事件,形成了有效分工、各司其職不塞車的 事件循環(Event Loop) 機制。

為了解 JavaScript 在瀏覽器中的 Event Loop,必須先認識以下名詞:Stack(堆疊)、Queue(佇列)

## Stack (堆疊)

Stack 是資料結構的一種,想像它是一個開口向上的容器,只有從這個開口才能將東西置入 (push) 或拿出來 (pop),並且一次一個為單位。

[台大資工系的C++程式設計課程] 中也有更生活化的舉例:

平常生活有時候也會發生 Stack 的情境,人會最優先處理最後發生的事

做事做到一半時,突然一件更緊急的事發生

這時就會先把打斷的事做完,才回來繼續做原來的事

又如

河內塔 故事中的每一個柱子都是 Stack 結構

柱子最上方的盤子,一定是最先被拿起來的

而在本篇的影片中,講者也實際拆解一段程式碼的執行流程來演示堆疊的過程:

堆疊的資料結構遵循著:先進後出、後進先出的規律。 在 Call Stack 中,先進來的主程式在它裡面的函式通通執行完後才結束;中途才加入 Call Stack 的函式必須優先執行,執行完便離開執行緒,讓 Call Stack 中剩下的主程式繼續執行至結束。

## Queue (佇列)

佇列是另一種資料結構,與堆疊最大的不同是:它是一個 先進先出的有序串列(Ordered list)。資料從後端加入(enqueue),從前端拿出(dequeue),即佇列這個容器的開口在兩端,先來的事情先處理。在 [資料結構:以Visual Basic實作](https://epaper.gotop.com.tw/pdf/AEE032400.pdf) 這本書中提到例如排隊買票、排隊結帳等都是佇列在生活中的例子。

## JavaScript 的 Event Loop

那麼在瀏覽器中 JavaScript 引擎是如何將程式中的事件安排先後順序、不造成塞車又能順暢運行的呢?首先要提到 JavaScript 作為單執行緒語言,容易塞車的情況:

### Blowing the Stack

例如在函式中呼叫同一個函式,使事件不斷堆疊至 overflow 的狀態,要特別注意:

### Blocking

當 Call Stack 中的事件一多起來,例如跑一萬次的迴圈,就會造成卡慢塞車,這就稱為 Blocking。當我們在程式中載入資料,此時 JavaScript 作為單執行緒的語言,必須先獲取資料才能執行接下來的程式,這時就造成了 Blocking,除了等待載入完成,什麼都不能做。

在瀏覽器中 為了解決這一問題,使用了 非同步呼叫(Asynchronus callback),讓我們得以在執行主程式的同時呼叫非同步資料,等待資料載入(排入佇列)的時間我們還是能夠正常使用網頁其他功能(主程式排入堆疊),待堆疊事件清空後,畫面載入資料(非同步呼叫離開佇列)再將資料渲染進來(進入堆疊)。

以下是講者將較完整的 JavaScript Event Loop 在瀏覽器中運行的狀況模擬出來,選一段目前看的懂的節錄於此:

在這個程式中我們可以看到,程式開始運行後,一行一行的執行,將待辦事件放入 Call Stack 中,遇到 setTimeout 之後將它放入 Callback Queue 中;另一邊 Call Stack 中還在執行主程式,順序是較晚進來的事件優先處理,最後待主程式執行完畢並清空後,Callback Queue 才開始把先進來的事件推到 Call Stack 中執行。

也從這個模擬可以看出瀏覽器在執行 JavaScript 程式碼時,面對同步與非同步資料是如何排定優先順序、如何分工同時處理。

## 後記

雖然整理完之後有稍微對瀏覽器中 JavaScript 運行方式較為理解,但畢竟是自己對初次聽到的觀念做的學習筆記,仍然有些原理還不是很通透,待學習到更多更深之後回來編輯,看有什麼地方沒有解釋清楚、甚至是觀念錯誤的,再來改進。若有理解錯誤的地方,歡迎留言懇請不吝指教!

## 參考資料

[JavaScript — Event Loop](https://ithelp.ithome.com.tw/articles/10230871)
[堆疊(stack) 資料結構](https://https://www.csie.ntu.edu.tw/~b98902112/cpp_and_algo/cpp02/stack.html)
[佇列 Queue](https://epaper.gotop.com.tw/pdf/AEE032400.pdf)
[What the heck is the event loop anyway? | Philip Roberts | JSConf EU](https://www.youtube.com/watch?v=8aGhZQkoFbQ&feature=youtu.be)

--

--