[譯] React Profiler 介紹

CoderMing發表於2019-03-04

React 16.5 新增了對新的 profiler DevTools 外掛的支援。這個外掛使用 React 的 Profiler 實驗性 API 去收集所有 component 的渲染時間,目的是為了找出你的 React App 的效能瓶頸。它將會和我們即將釋出的 時間片 特性完全相容。(譯者注:可以參考 Dan 在第一屆中國 React 開發者大會上的視訊

這篇博文包括以下的話題:

Profile 一個 APP

DevTools 將會對支援新的 profiling API 的 APP 新加一個 “Profiler” tab 列:

New DevTools

Note:react-dom 16.5+ 在 DEV 模式下才支援 Profiling,同時生產環境下也可以通過一個 profiling bundle react-dom/profiling 來支援。請在 fb.me/react-profi… 上檢視如何使用這個 bundle。

這個 “Profiler” 的皮膚在剛開始的時候是空的。你可以點選 record 按鈕來啟動 profile:

Click

當你開始記錄之後,DevTools 將會自動收集你 APP 在(啟動之後)每一刻的效能資料。(在記錄期間)你可以和平常一樣使用你的 APP,當你完成 profile 之後,請點 “Stop” 按鈕。

Click

如果你的 APP 在 profile 期間重新渲染了幾次,DevTools 將會提供好幾種方法去檢視效能資料。我們將會 在接下來討論它們

檢視效能資料

瀏覽 commits

從概念上講,React 的執行分為兩個階段:

  • render 階段會確定例如 DOM 之類的資料需要做那些變化。在這個階段,React 將會執行(各個元件的)render 方法,之後會計算出和呼叫 render 方法之前有哪些變化。
  • commit 階段是 React 提交任何更改所在的階段(在 React DOM 下,就是指 React 新增、修改和移除 DOM 節點的時候)。同時在這個階段,React 會執行像 componentDidMountcomponentDidUpdate 這類周期函式。

(譯者注:此處可參考 React.js 小書第 18-20 篇

profiler DevTools 是在 commit 階段收集效能資料的。各次 commit 會被展示在介面頂部的條形圖中:

Bar chart of profiled commits

在條形圖中,每一列都表示單次的 commit 資料,你當前選中的 commit 列會變成黑色。你可以點選各個列(或者是左/右切換按鈕)來檢視不同的 commit 資料。

這些列的顏色和高度對應著該次 commit 在渲染上所花的時間(較高、偏黃的列會比較矮、偏藍的列花費的時間多)。

篩選 commits

你 profile 的記錄時間越長,渲染次數就會越多。有時候你或許會被過多的(價值低的)commit 記錄干擾。為了幫助你解決這個問題,profiler 提供了一個篩選功能。用它來制定一個時間閥值,之後 profiler 會隱藏所有比這個閥值更快的 commit。

Filtering commits by time

火焰圖

(譯者注:阮一峰:如何讀懂火焰圖?

火焰圖會展示你所指定的那一次 commit 的資訊。圖中每一列都代表了一個 React component(例如下圖中的 AppNav)。各列的尺寸和顏色表示這列所代表的 component 及其 children 的渲染時間(列的寬度表示該 component 最近一次渲染所花費的時間,列的顏色代表在該次 commit 中渲染所花費的時間)。

Example flame chart

Note:

列的寬度表示 component(和它的 children)最近一次渲染所花費的時間。如果這個 component 在本次 commit 中沒有被重新渲染,那其所展示的時間表示上一次 render 的耗時。一個列越寬,其所代表的 component 渲染耗時就越長。

列的顏色表示在本次 commit 中該 component(和它的 children)所花費的時間。黃色代表耗時較長、藍色代表耗時較短,灰色代表該 component 在這次 commit 中沒有被(重新)渲染。

舉個例子,上圖中所展示的 commit 總共渲染耗時為 18.4 ms。Router component 是渲染成本“最昂貴”的 component(花費了 18.4 ms)。他所花費的時間大部分在兩個 children 上:Nav(8.4 ms)和 Route (7.9 ms)。剩下的時間用於它的其他 children 和它自身的渲染。

你可以通過點選 component 列來放大或縮小火焰圖:

Click on a component to zoom in or out

點選一個 component 的同時也會選中它,它的具體資訊將會展示在右邊的資料列,列裡會展示該 component 在這次 commit 時的 propsstate。你可以去深入研究這些資料來找出這次 commit 具體做了哪些。

Viewing a component`s props and state for a commit

某些情況下,選中一個 component 後在不同的 commit 之間切換也可以發現觸發這次渲染的原因:

Seeing which values changed between commits

上圖表示在兩次 commit 中 state.scrollOffset 被改變了。這或許就是觸發 List component 重繪的原因。

排序圖

同火焰圖一樣,排序圖也會展示你所指定的那一次 commit 的資訊,圖中每一列都代表了一個 React component(例如下圖中的 AppNav)。不同的是排序圖是有順序的,耗時最長的 component 會展示在第一行。

Example ranked chart

Note:

一個 component 的渲染時間也包括了它的 children 們消耗的時間,所以渲染耗時最長的 component 通常距離樹頂部最近。

和火焰圖一樣,你可以通過點選 component 列來放大或縮小排序圖(譯者注:排序圖只會展示在本次 commit 中被觸發重繪的 component)。

Component 圖

在你 profile 的過程中,使用該圖檢視單一 component(在多次 commit 中)的渲染時間有時候是非常有用的。Component 圖會以一個列的形式展示,其中每一列都表示你所選擇的 component 的某一次 commit 下的渲染時間。每列高度和顏色都表示該 component 在某次 commit 中同其它元件的耗時對比。

Example component chart

上圖表明 List component 渲染了 11 次。同時還表明 List 在每次渲染中是最“昂貴”的元件。(譯者注:此處是通過列的顏色判斷)

檢視這種圖的方法有兩種:雙擊一個 component 或者是選中一個 component 後點選在右邊列中的藍色表格按鈕。你可以通過點選右邊列的 “x” 按鈕來返回原圖,當然你也可以雙擊 Component 圖中的某一列來檢視那次 commit 的更多資訊。

How to view all renders for a specific component

如果你所選中的 component 在 profile 期間從來沒被渲染過,則會顯示下面的資訊:

No render times for the selected component

互動動作(Interactions)

React 最近新增了一個 實驗性 API,目的是為了追蹤引起更新的原因。被這些API所追蹤的“互動動作”也會展示在 profiler 裡:

The interactions panel

上圖展現了一個 profile 期間被追蹤的 4 個互動動作。每行都展示了一個追蹤的互動動作。每行裡帶有顏色的點表示與其互動動作所對應的 commit 記錄。

你也可以在特定的 commit 記錄的右邊列看到在該記錄期間所被追蹤的互動動作。

List of interactions for a commit

你可以通過點選它們來實現在互動動作和 commits 之間的跳轉:

Navigate between interactions and commits

tracking API 仍然是很新的特性,我們會在接下來的部落格文章中詳細介紹它。

常見問題 & 解決方法

選擇的根元素下沒有 profile 資料被記錄

如果你的 APP 有好幾個 “root”(譯者注:指 React 有好幾個 root 元件),你可能會在 profile 之後看到下面的資訊:

No profiling data has been recorded for the selected root

這個資訊表示你在 “Elements” 介面下所選擇的 root 之下沒有效能資料被記錄。這種情況下,請嘗試選擇一個不同的根元素來檢視在這個 root 下的 profile 資料:

`Select

選中的 commit 記錄沒有時間資料可以展示

有時候 commit 速度可能非常地快,以至於 performance.now() 沒法提供給 DevTools 任何有意義的資料。這種情況下,會展示下面的介面:

No timing data to display for the selected commit

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。

掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專列

相關文章