會用 Performance 工具,就能深入理解 Event Loop
網(wǎng)頁加載后,瀏覽器會解析 html、執(zhí)行 js、渲染 css,這些工作都是在 Event Loop 里完成的,理解了 Event Loop 就能理解網(wǎng)頁的運行流程。
但很多人對 Event Loop 的理解只是停留在概念層面,并沒看過真實的 Event Loop 是怎樣的。
其實在 Performance 工具里就可以看到,今天我們一起來看一下:
首先我們需要一個網(wǎng)頁,我這里用的是 react 測試 fiber 用的網(wǎng)頁:
https://claudiopro.github.io/react-fiber-vs-stack-demo/fiber.html

點擊 Performance 面板的 reload,錄制 3 s 的數(shù)據(jù):

其中 Main 這部分就是網(wǎng)頁的主線程,也就是執(zhí)行 Event Loop 的部分:

這塊區(qū)域包含了所有 task 執(zhí)行的流程,每個 task 的調(diào)用棧,因為像燃燒的火焰,所以也叫做火焰圖。
鼠標(biāo)劃到想看的部分,向下拖動,就可以放大那個區(qū)域:

左右拖動可以調(diào)整看的位置:

展示的信息中很多種顏色,這些顏色代表著不同的含義:
灰色就代表宏任務(wù) task:

藍(lán)色的是 html 的 parse,橙色的是瀏覽器內(nèi)部的 JS:

紫色是樣式的 reflow、repaint,綠色的部分就是渲染:

其余的顏色都是用戶 JS 的執(zhí)行了,那些可以不用區(qū)分。
怎么從 Performance 中看出 Event Loop 執(zhí)行的流程呢?
我們一起來看一下:
你會發(fā)現(xiàn)每隔一段時間就會有一個這種任務(wù):

放大一下是這樣的:

執(zhí)行了 Animation Frame 的回調(diào),然后執(zhí)行了回流重繪,最后執(zhí)行渲染。
這種任務(wù)每隔 16.7 ms 就會執(zhí)行一次:

這就是網(wǎng)頁里怎么執(zhí)行渲染的。
所以說 requestAnimationFrame 的回調(diào)是在渲染前執(zhí)行的,rAF 和渲染構(gòu)成了一個宏任務(wù)。
為什么有的時候會掉幀、卡頓,就是因為阻塞的渲染的宏任務(wù)的執(zhí)行:

(在 Performance 中寬度代表時間,超過 200ms 就被認(rèn)為是 Long Task,會被標(biāo)紅)
我們做性能分析,就是要找到這些 Long Task,然后優(yōu)化掉它。
那除了 rAF 和渲染,還有哪些是宏任務(wù)呢?
看下分析的結(jié)果就知道了:
可以看到 requestIdleCallback 的回調(diào)是宏任務(wù):

垃圾回收 GC 是宏任務(wù):

requestAnimationFrame 的回調(diào)是宏任務(wù):

html 中直接執(zhí)行的 script 也是宏任務(wù):

這些需要記么?
不需要,用 Performance 工具看下就知道了。
那微任務(wù)是怎么執(zhí)行的呢?

可以看到 micro task 只是 task 的一部分,宏任務(wù)執(zhí)行完就會執(zhí)行所有的微任務(wù)。
這就是這個網(wǎng)頁的 Event Loop 執(zhí)行過程。
當(dāng)你對這些熟悉了之后,看到下面的火焰圖,你就能分析出一些東西來了:

中間比較寬的標(biāo)紅的就是 Long Task,是性能優(yōu)化的主要目標(biāo)。
一些比較窄的周期性的 Task 就是 requestAnimationFrame 回調(diào)以及 reflow、rapaint 和渲染。
比較長的那個調(diào)用棧一般是遞歸,而且遞歸層數(shù)特別多。
當(dāng)你展開看的時候,它也能展示完整的代碼運行流程:

而如果你打斷點調(diào)試,只能看到其中的一個調(diào)用棧,這是用 Performance 工具分析代碼流程比 debugger 斷點調(diào)試更好的地方。
當(dāng)你閱讀源碼的時候,也可以通過 Performance 看執(zhí)行流程的全貌,然后再 debugger 某些具體的流程。
總結(jié)
Performance 工具能夠看到網(wǎng)頁的 Event Loop 是怎么運行的,不同的顏色代表不同的含義:
- 灰色:task
- 橙色:瀏覽器內(nèi)部的 JS
- 藍(lán)色:html parse
- 紫色:reflow、repaint
- 綠色:渲染
其余的顏色都是用戶自己的 JS。
寬度代表了執(zhí)行的時間,超過 200ms 就被任務(wù)是長任務(wù),需要優(yōu)化。
長度代表了調(diào)用棧深度,一般特別長的都是有遞歸在。
用 Performance 工具可以分析出很多東西:
- rAF 回調(diào)和 reflow、repaint 還有渲染構(gòu)成一個宏任務(wù),每 16.7 ms 執(zhí)行一次。
- rAF 回調(diào)、rIC 回調(diào)、GC、html 中的 script 等都是宏任務(wù)
- 在任務(wù)執(zhí)行完后,瀏覽器會執(zhí)行所有微任務(wù),也就是 runAllMicroTasks 部分
Performance 可以看到代碼執(zhí)行全貌,而斷點調(diào)試的調(diào)用棧只能看到某一條流程。所以調(diào)試代碼的時候可以 Performance 和 Debugger 結(jié)合來看。
總之,會用 Performance 工具,你就能深入理解 Event Loop,理清網(wǎng)頁執(zhí)行的全流程。





























