淺析 JS 事件循環之 Microtask 和 Macrotask

簡介

我們在上一篇 《淺析 JS 中的EventLoop 事件循環》 中提到一個 Event Queue,其實在事件循環中 queue 一共有兩種,還有一種叫 Job Queue

其中

Event Queue 在 HTML 規範中被稱爲 Task Queue,但是爲了區分,一般都叫作 Macrotask Queue
Job Queue 是在 ECMAScript 規範中談及處理 Promise 回調時提到的,但是由於和 V8 中的實現比較相似,所以一般都稱爲 Microtask Queue

Macrotask

Macrotasks 包含了解析 HTML、生成 DOM、執行主線程 JS 代碼和其他事件如 頁面加載、輸入、網絡事件、定時器事件等。從瀏覽器的角度,Macrotask 代表的是一些離散的獨立的工作。

常見應用
setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering

Microtask

Microtasks 則是爲了完成一些更新應用程序狀態的較小的任務,如處理 Promise 的回調和 DOM 的修改,以便讓這些任務在瀏覽器重新渲染之前執行。Microtask 應該以異步的方式儘快執行,所以它們的開銷比 Macrotask 要小,並且可以使我們在 UI 重新渲染之前執行,避免了不必要的 UI 渲染。

常見應用
process.nextTick, Promises, Object.observe, MutationObserver

執行順序

Event Loop 的實現需要至少一個 Macrotask Queue 和至少一個 Microtask Queue。爲了便於理解,我們都簡化成一個。
簡單來說,Microtask Queue 具有更高的優先級,即執行一個 Macrotask 任務後,就會清空整個 Microtask Queue,此時如果有新的 Microtask 加入也會被執行。

所以我們來看下面的代碼:
圖片描述

執行順序是什麼?
我們已經知道 setTimeout 是 Macrotask,Promise 是 Microtask,而這段代碼從上到下執行也是一個 Macrotask

步驟:

  1. 開始執行,執行腳本作爲一個任務進入 Macrotask Queue,同時進入調用棧執行
  2. Line 1, 輸出 script start
  3. Line 3 的 setTimeout 回調進入 Macrotask Queue 等待
  4. Line 7 的回調進入 Microtask Queue 等待
  5. Line 13 輸出 script end,此時腳本執行完成(即完成了一個 Macrotask)
  6. 開始執行 Microtask Queue,從中拿出一個放入調用棧執行
  7. 開始執行 Line 7 的回調,該回調輸出 promise1,返回 undefined
  8. Line 9 的回調進入 Microtask Queue,由於 Microtask Queue 沒有清空,直接執行該回調,輸出 promise2,該回調返回 undefined
  9. Microtask Queue 已清空(此時瀏覽器可以更新渲染UI),開始將 Macrotask Queue 中任務放入調用棧執行
  10. 執行 Line 3 的回調,輸出 setTimeout,Macrotask Queue 清空
  11. 程序執行完成

所以打印順序爲:

script start -> script end -> promise1 -> promise2 -> setTimeout

PS. 上面的這段代碼執行流程,建議看原文的倒數第二篇參考文章,有動態交互操作可以演練。

總結

microtask-macrotask.png

  1. Microtask 相比 Macrotask 具有更高的優先級
  2. Macrotask 總是在 JS 代碼執行完成並且 Microtask Queue 清空之後執行
  3. JS 代碼執行本身也是一個 Macrotask
  4. Microtask Queue 清空後有可能會重新渲染 UI
  5. Promise 屬於 Microtask,setTimeout 屬於 Macrotask

總體的執行順序爲:常規代碼 -> promises -> events 和 setTimeout 等

參考文章

原文鏈接
ECMA262 Job Queues
HTML Standard Task Queue
HTML系列:macrotask和microtask
microtask and macrotask a hands on approach
difference-between-microtask-and-macrotask-within-an-event-loop-context

公衆號:碼力全開
bVbrEUH?w=258&h=258

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章