[筆記] Javascript 的 Event Loop
注意 ! 這篇不是教學或心得文,只是個人紀錄而已。
Javascript 是個事件驅動的語言 , 且有非同步的特性 , 所以在初學時可能要花點時間搞懂這三個東西 :
(1)同步 / 異步
(2)Callback
(3)Event Loop
因為 Javascript 設計之初就是單線程語言,因此為了實現主線程的不阻塞,Event Loop 這樣的方案應運而生。這邊紀錄一下Event Loop的執行方式
這些圖是 參考1 參考2,這篇也講得蠻清晰的,引用一下重點 :
同步和異步任務分別進入不同的執行 "場所 ",同步的進入主線程,異步的進入Event Table並註冊函數。
當指定的事情完成時,Event Table會將這個函數移入Event Queue。
主線程內的任務執行完畢為空,會去Event Queue讀取對應的函數,進入主線程執行。
上述過程會不斷重複,也就是常說的Event Loop(事件循環)。
有點繞口,總之重點就是 javascript 在執行時為了實現 非同步管理 ,所以需要這樣的機制 。 程式執行時 , 先判斷是否為同步任務 ? 若是,則直接執行 ; 若否,則納入 Event Queue 中等待 。
而 Event Queue 中又分為 :
- macro-task:包括整體代碼script,setTimeout,setInterval
- micro-task:Promise,process.nextTick(優先權較 Promise高)
同步任務執行完後,會執行 micro-task ,接著再判斷有沒有 macro-task ,執行完後再檢查有沒有 micro-task ,如此反覆直到執行完畢。
以下為網上的範例
console.log(1)
setTimeout(() => {
console.log(2)
new Promise(resolve => {
console.log(4)
resolve()
}).then(() => {
console.log(5)
})
})
new Promise(resolve => {
console.log(7)
resolve()
}).then(() => {
console.log(8)
})
setTimeout(() => {
console.log(9)
new Promise(resolve => {
console.log(11)
resolve()
}).then(() => {
console.log(12)
})
})
分析如下:
同步運行的代碼首先輸出:
1、7
接著,清空microtask隊列:
8
第一個task執行:
2、4
接著,清空microtask隊列:
5
第二個task執行:
9、11
接著,清空microtask隊列:
12
他的執行結果會是 1 , 7 , 8 , 2 , 4 , 5 , 9 , 11 , 12
但實際在本機端執行結果卻是 1, 7, 8, 2, 4, 9, 11, 5, 12
原因在於執行 macro-task 跟 micro-task 的邏輯順序不一樣
而在其他篇有看到這樣一句
(請注意,node環境下的事件監聽依賴libuv與前端環境不完全相同,輸出順序可能會有誤差)
故研判可能與 v8 環境與本機 node 環境執行有所差異所致 。