[筆記] 理解 Event Loop,Call Stack, Event & Job Queue in Javascript
JavaScript 最大的優點就是它能夠直接在瀏覽器中運行,不需要任何設置,只需要打開新的瀏覽器並使用 JavaScript 控制台即可執行程式碼。
在瀏覽器中,JavaScript 不僅僅是 Runtime engine ( 運行引擎 ) ,還有許多其他的功能,例如:Web Apis ( ex: DOM 、 setTimeout ), callback queue ( 回調序列 ) 以及 event loop ( 事件循環 )。
JavaScript Runtime engine ( 運行引擎 )
每個瀏覽器都有自己的 JS Runtime engine,最著名的就是 google chrome 的 V8 JavaScript 引擎
Event Loop 視覺化圖
Heap
JS Runtime 的 Memory Heap 進行記憶體的分配,呼叫堆疊 Call Stack
。
Stack
JavaScript 逐一執行程式碼的地方稱為堆疊 Stack
,當有程式碼片段需要執行就會形成一個frame
被堆疊進Stack
等待,一旦執行完該frame
就會跳出。
如果是異步執行的程式碼,例如 : setTimeout()、ajax()、Promise、或是 onClick()事件,程式碼會從主堆疊( main stack )中移動到事件表(event table)中。
如果在函式中執行return
,該函式則會在 stack 中直接抽離出來。
Web APIS
是指瀏覽器額外提供的東西,(ex: DOM、Ajax、setTimeout,etc)
Callback Queue
異步執行的程式碼會被推到這裏並等待執行。
Event Loop
接著會來到事件循環,該事件會連續不斷地監聽Stack
中是否還有待執行的程式碼片段。
確認沒有後就換檢查Callback Queue
, 如果Callback Queue
有準備好的Callback
,Event Loop
會將第一個準備好的Callback
移動到Stack
中執行。
Job Queue
除了Callback Queue
,瀏覽器還有另一個佇列叫做Job Queue
,這個佇列只保留新功能Promise()
的frame
。
當使用到Promise()
時即新增了一個 thenable method
,而 thenable method
會被加入到 Job Queue 中,當執行完畢後回傳一個 returned 或是 resolved。
single threaded : JavaScript 是一種單執行緒的程式語言,所有的程式碼會被 stack 中逐一執行,一次只執行一段程式碼。
Blocking 阻塞
當 main stack
具有影響效能的程式碼在某個frame
中,其他的程式碼片段就必須等待該frame
執行完畢才能有其他的動作(ex: onClick())),稱為 阻塞 。
Quick Question now
試著預測下面的輸出結果:
1 | console.log("message no. 1: Sync"); |
有些人可能會預測結果為:
1 | //message no. 1: Sync |
但事實上結果為:
1 | //message no. 1: Sync |
為什麼呢? 這是因為 Job Queue
有較高的優先權,所以當主堆疊中的frame
執行完後, Event Loop
會優先檢查及執行 Job Queue
裡的作業,全部執行完後才會到 `Callback Queue。
Code execution notes
async code
會在main stack
全部執行完畢後才開始執行。main stack
中當下的statements
及functions
會執行完畢,過程中無法被async code
中斷。因為須等待
main stack
執行完畢,因此不能保證async code
將在指定的時間準確執行,如果main stack
正忙於執行當下的程式,那async code
將被延遲。就算
setTimeout()
延遲時間設定為 0 ,程式也不會立即被執行,依然會被排在Callback Queue
等待main stack
結束。
1 | setTimeout(() => { |
結果為:
1 | // message no. 2: Sync |