會用 Performance 工具,就能深入理解 Event Loop

網頁加載後,瀏覽器會解析 html、執行 js、渲染 css,這些工作都是在 Event Loop 裏完成的,理解了 Event Loop 就能理解網頁的運行流程。

但很多人對 Event Loop 的理解只是停留在概念層面,並沒看過真實的 Event Loop 是怎樣的。

其實在 Performance 工具裏就可以看到,今天我們一起來看一下:

首先我們需要一個網頁,我這裏用的是 react 測試 fiber 用的網頁:

https://claudiopro.github.io/react-fiber-vs-stack-demo/fiber.html

點擊 Performance 面板的 reload,錄製 3 s 的數據:

其中 Main 這部分就是網頁的主線程,也就是執行 Event Loop 的部分:

這塊區域包含了所有 task 執行的流程,每個 task 的調用棧,因爲像燃燒的火焰,所以也叫做火焰圖。

鼠標劃到想看的部分,向下拖動,就可以放大那個區域:

左右拖動可以調整看的位置:

展示的信息中很多種顏色,這些顏色代表着不同的含義:

灰色就代表宏任務 task:

藍色的是 html 的 parse,橙色的是瀏覽器內部的 JS:

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

其餘的顏色都是用戶 JS 的執行了,那些可以不用區分。

怎麼從 Performance 中看出 Event Loop 執行的流程呢?

我們一起來看一下:

你會發現每隔一段時間就會有一個這種任務:

放大一下是這樣的:

執行了 Animation Frame 的回調,然後執行了迴流重繪,最後執行渲染。

這種任務每隔 16.7 ms 就會執行一次:

這就是網頁裏怎麼執行渲染的。

所以說 requestAnimationFrame 的回調是在渲染前執行的,rAF 和渲染構成了一個宏任務。

爲什麼有的時候會掉幀、卡頓,就是因爲阻塞的渲染的宏任務的執行:

(在 Performance 中寬度代表時間,超過 50ms 就被認爲是 Long Task,會被標紅)

我們做性能分析,就是要找到這些 Long Task,然後優化掉它。

那除了 rAF 和渲染,還有哪些是宏任務呢?

看下分析的結果就知道了:

可以看到 requestIdleCallback 的回調是宏任務:

垃圾回收 GC 是宏任務:

requestAnimationFrame 的回調是宏任務:

html 中直接執行的 script 也是宏任務:

這些需要記麼?

不需要,用 Performance 工具看下就知道了。

那微任務是怎麼執行的呢?

可以看到 micro task 只是 task 的一部分,宏任務執行完就會執行所有的微任務。

這就是這個網頁的 Event Loop 執行過程。

當你對這些熟悉了之後,看到下面的火焰圖,你就能分析出一些東西來了:

中間比較寬的標紅的就是 Long Task,是性能優化的主要目標。

一些比較窄的週期性的 Task 就是 requestAnimationFrame 回調以及 reflow、rapaint 和渲染。

比較長的那個調用棧一般是遞歸,而且遞歸層數特別多。

當你展開看的時候,它也能展示完整的代碼運行流程:

而如果你打斷點調試,只能看到其中的一個調用棧,這是用 Performance 工具分析代碼流程比 debugger 斷點調試更好的地方。

當你閱讀源碼的時候,也可以通過 Performance 看執行流程的全貌,然後再 debugger 某些具體的流程。

總結

Performance 工具能夠看到網頁的 Event Loop 是怎麼運行的,不同的顏色代表不同的含義:

其餘的顏色都是用戶自己的 JS。

寬度代表了執行的時間,超過 50ms 就被任務是長任務,需要優化。

長度代表了調用棧深度,一般特別長的都是有遞歸在。

用 Performance 工具可以分析出很多東西:

Performance 可以看到代碼執行全貌,而斷點調試的調用棧只能看到某一條流程。所以調試代碼的時候可以 Performance 和 Debugger 結合來看。

總之,會用 Performance 工具,你就能深入理解 Event Loop,理清網頁執行的全流程。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/22tS74K5JQr1V98Q4DPqJg