JS JavaScript事件迴圈機制
JS JavaScript事件迴圈機制
首先區分程序和執行緒
- 程序是
cpu
資源分配的最小單位(系統會給它分配記憶體) - 不同的程序之間是可以同學的,如管道、
FIFO
(命名管道)、訊息佇列 - 一個程序裡有單個或多個執行緒
- 瀏覽器是多程序的,因為系統給它的程序分配了資源(
cpu
、記憶體)(開啟Chrome
會有一個主程序,每開啟一個Tab
頁就有一個獨立的程序)
瀏覽器的渲染程序是多執行緒的
GUI JS HTTP
事件迴圈機制
上圖解釋:
- 同步和非同步任務分別進入不同的執行"場所",同步的進入主執行緒,非同步的進入
Event Table
並註冊函式 - 當指定的事情完成時,
Event Table
會將這個函式移入Event Queue
- 當棧中的程式碼執行完畢,執行棧(
call stack
)中的任務為空時,就會讀取任務佇列(Event quene
)中的事件,去執行對應的回撥 - 如此迴圈,形成js的事件迴圈機制(
Event Loop
)
巨集任務(macrotask)和微任務(microtask)
先看一段程式碼的執行結果:
console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); console.log('script end');
執行結果: script start , script end , promise1 , promise2 , setTimeout
JS中分為兩種任務型別: macrotask
和 microtask
,在 ECMAScript
中, microtask
稱為 jobs
, macrotask
可稱為 task
-
macrotask
(又稱之為巨集任務),可以理解是每次執行棧執行的程式碼就是一個巨集任務(包括每次從事件佇列中獲取一個事件回撥並放到執行棧中執行)
- 每一個
task
會從頭到尾將這個任務執行完畢,不會執行其它 - 瀏覽器為了能夠使得
JS
內部task
與DOM
任務能夠有序的執行,會在一個task
執行結束後,在下一個task
執行開始前,對頁面進行重新渲染 (task
->渲染->task
->...)
-
microtask
(又稱為微任務),可以理解是在當前task
執行結束後立即執行的任務
- 也就是說,在當前
task
任務後,下一個task
之前,在渲染之前 - 所以它的響應速度相比
setTimeout
(setTimeout
是task
)會更快,因為無需等渲染 - 也就是說,在某一個
macrotask
執行完後,就會將在它執行期間產生的所有microtask
都執行完畢(在渲染前)
分別什麼樣的場景會形成macrotask和microtask呢?
-
macrotask
:主程式碼塊,setTimeout
,setInterval
等(可以看到,事件佇列中的每一個事件都是一個macrotask
) -
microtask
:Promise
,process.nextTick
等
補充:在node環境下,process.nextTick的優先順序高於Promise,也就是可以簡單理解為:在巨集任務結束後會先執行微任務佇列中的nextTickQueue部分,然後才會執行微任務中的Promise部分。
總結下執行機制:
GUI JS
如圖: