首頁>技術>

作者 | Addy Osmani

譯者 | 許學文

策劃 | 蔡芳芳

本文最初發佈於Addy Osmani部落格,經原作者授權由 InfoQ 中文站翻譯並分享

今天我將向大家演示如何使用 React Profiler API、Tracing API 以及 User Timing API 來分別追蹤 React 的元件渲染、使用者互動以及自定義效能指標。

React Profiler API

首先來了解下 React Profiler,它主要用來追蹤應用元件的 渲染過程 以及渲染開銷,同時標記出應用的效能瓶頸。Profiler 接受一個 onRender 回撥函式,當被追蹤的元件以及子代元件發生更新時,該函式就會被呼叫。下圖是在影片排期應用中使用 Profiler 追蹤各個元件渲染:

Profiler 中 onRender 回撥函式的具體引數如下:

id:: 這是 Profiler 的唯一標示,區分是哪個 Profiler 追蹤的元件樹發生了更新phase: 如果更新是掛載階段這個值就是“mount”,如果是二次渲染階段就是“update”act ualDuration: 更新花費的渲染時間baseDuration: 更新預計花費的渲染時間startTime: 更新開始時間點commitTime: 更新提交的時間點interactions: 更新中包含的互動資訊const callback = (id, phase, actualTime, baseTime, startTime, commitTime) => {    console.log(`${id}'s ${phase} phase:`);    console.log(`Actual time: ${actualTime}`);    console.log(`Base time: ${baseTime}`);    console.log(`Start time: ${startTime}`);    console.log(`Commit time: ${commitTime}`);}

執行上面的程式碼,在 Chrome 偵錯程式中可以看到如下輸出:

也可以開啟 React DevTools,在 Profiler 面板中可以看到元件渲染的時間火焰圖:

切換到排序檢視

當然也可以使用多個 Profiler 來分別追蹤應用中的各個不同的部分,示例程式碼如下:

import React, { Fragment, unstable_Profiler as Profiler} from "react";render(  <App>    <Profiler id="Header" onRender={callback}>      <Header {...props} />    </Profiler>    <Profiler id="Movies" onRender={callback}>      <Movies {...props} />    </Profiler>  </App>)

知道了如何追蹤元件渲染,那麼如果想跟蹤互動,該怎麼做?

互動追蹤 Tracing API

想一下,如果能追蹤到互動(例如:按鈕的點選),那麼在回答“這個按鈕點選花費了多少時間更新 DOM?”這樣的問題時是不是就有了依據。要感謝 Brian Vaughn 的努力,React 在其 排程包 中引入了對這個功能的試驗支援,更詳細的說明可以點選 這裡 檢視。

一個互動追蹤,需要包含一個描述(例如:新增購物車按鈕被點選)、一個時間戳和一個回撥函式,在回撥函式中你可以定義一些和該互動相關的邏輯。在“影片排期應用”中就有一個新增電影到播放列表的“+”號按鈕,這個就是一個互動按鈕。

import { unstable_Profiler as Profiler } from "react";import { render } from "react-dom";import { unstable_trace as trace } from "scheduler/tracing";class MyComponent extends Component {  addMovieButtonClick = event => {    trace("Add To Movies Queue click", performance.now(), () => {      this.setState({ itemAddedToQueue: true });    });  };

在 React 開發除錯工具的 interaction 面板中可以看到具體的互動行為和持續時間:

這個 API 同樣也可以 追蹤初始化渲染:

Brian 提供了更多的例子,比如如何追蹤非同步行為等。這些示例都在其“React 中進行互動追蹤”專案的 gist 中。

Puppeteer 的使用

如果想對 UI 互動追蹤指令碼做進一步了解的話,你可能會對 Puppeteer 這個庫感興趣。Puppeteer 是一個 Node 庫,基於 Chrome 開發協議封裝 API 來操作 headless Chrome(譯者注:Chrome 瀏覽器對無介面形態)。

為了捕獲 DevTools 對當前執行程式效能的追蹤,Puppeteer 提供了 trace .start() 和 trace.stop() 兩個 API,下面我們就用它來追蹤按鈕點選的過程,程式碼如下::

const puppeteer = require('puppeteer');(async () => {  const browser = await puppeteer.launch();  const page = await browser.newPage();  const navigationPromise = page.waitForNavigation();  await page.goto('https://react-movies-queue.glitch.me/')  await page.setViewport({ width: 1276, height: 689 });  await navigationPromise;  const addMovieToQueueBtn = 'li:nth-child(3) > .card > .card__info > div > .button';  await page.waitForSelector(addMovieToQueueBtn);  // 開始追蹤...  await page.tracing.start({ path: 'profile.json' });  // 按鈕點選  await page.click(addMovieToQueueBtn);  // 停止追蹤  await page.tracing.stop();  await browser.close();

然後在開發工具的效能面板中匯入 profile.json,我們就可以看到當按鈕點選的時候,所有函式的呼叫情況:

如果你對互動追蹤感興趣並且想了解更多的話,不妨看看 Stoyan Stefanov 的“JavaScript 元件級別的 CPU 開銷”這篇文章。

客戶端效能追蹤 API

使用 客戶端效能追蹤 API 可以追蹤一些定製的效能指標,並且時間精確度會更高。它有 2 個主要的 API:

window.performance.mark(): 儲存當前 mark 執行時的時間戳window.performance.measure(): 儲存 2 個相同 mark 之間的執行時間

示例程式碼如下:

// 記錄任務開始之前的時間戳performance.mark('Movies:updateStart');// 這裡執行了一些任務...// 記錄任務結束的時間戳performance.mark('Movies:updateEnd');// 計算任務開始前後的差值performance.measure('moviesRender', 'Movies:updateStart', 'Movies:updateEnd'

當你通過 Chrome 除錯工具中的效能面板檢視一個 React 應用時,有一個“Timings”的區域,這裡歸集了你的 React 元件的執行時間。在渲染時,React 會把通過客戶端 API 得到的效能資料釋出到這裡。

注意:React 在它的開發包中用 Profiler 替代了 User Timings,不過由於 User Timings 的時間精度更高,所以可能會在未來的 3 級規格的瀏覽器中重新新增它。

在網際網路上,你會發現有一些其他的 React 應用已經在使用 User Timing 追蹤他們的 自定義指標,包括 Reddit 網站中的“到第一標題可見花費的時間”和 Spotify 網站中的“到回放準備完畢花費的時間”。

還可以在 Chrome 偵錯程式的 Lighthouse 面板 中檢視到定製化的 User Timing 標記和追蹤方法,如下圖:

在 Next.js 的最近版本中也針對一些事件 新增 了很多 User timing 標記和追蹤,例如:

Next.js-hydration: 混合持續時間Next.js-nav-to-render: 導航開始到開始渲染之間的時間

所有的這些追蹤都可以在偵錯程式的 Timings 區域看到:

對比 DevTools 和 Lighthouse

值得注意的是,Lighthouse 和 Chrome 除錯工具 中的效能面板都可以深入分析 React 應用程式的載入和執行時效能,使用者可以看到下面這些效能指標:

React 使用者可能會喜歡像 總阻塞時間 (TBT) 這樣的新指標,它量化一個頁面具體什麼時候才可以互動(可 互動時間), 下面我們可以看下在併發模式前後應用發生更新時,TBT 的情況:

Lighthouse 還為一些特定的效能場景提供了修改建議。如在 Lighthouse 6.0 中可以看到一個提示,建議我們移除 未使用的 JavaScript程式碼。Lighthouse 追蹤到了這個問題並且提醒我們可以使用 React.lazy () 來引入這個 JavaScript。

藉助使用者端的硬體進行效能智慧檢查,往往對效能分析非常有幫助。

最後,除了上面提到的我通常還會從 RUM 和 CrUX 獲取一些資料欄位,然後用 webpagetest.org/easy 工具幫我生成更多的場景圖片,以便更好的進行效能分析。

作者 | Addy Osmani

譯者 | 許學文

策劃 | 蔡芳芳

140

Chrome

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 碼農大叔打賭,github上快速搜尋優質開源專案,這些技能你不懂?