前言
今天,我们介绍一下如何使用 React Profiler API 分析 React 组件的渲染性能。
出于演示目的,我们将使用一个电影排队 APP 。
The React Profiler API
React Profiler API 会分析渲染和渲染成本,以帮助识别应用程序中卡顿的原因。
import React, { Fragment, unstable_Profiler as Profiler} from "react";
Profiler 接受一个 onRender 回调函数,当被分析的渲染树中的组件提交更新时,就会调用它。
const Movies = ({ movies, addToQueue }) => (
"Movies" onRender={callback}>
为了进行测试,让我们尝试使用 Profiler 来测量 Movies 组件各部分的渲染时间:
Profiler 的 onRender 回调接收描述渲染内容和所花费时间的参数:
- id: 生提交的 Profiler 树的 id。如果有多个 profiler,它能用来分辨树的哪一部分发生了“提交”。
- phase: “mount” (首次挂载) 或 “update” (重新渲染),判断是组件树的第一次装载引起的重渲染,还是由 props、state 或是 hooks 改变引起的重渲染。
- actualDuration: 次更新在渲染 Profiler 和它的子代上花费的时间。
- baseDuration: 在 Profiler 树中最近一次每一个组件 render 的持续时间。这个值估计了最差的渲染时间。
- startTime: 本次更新中 React 开始渲染的时间戳。
- commitTime: 本次更新中 React commit 阶段结束的时间戳。再一次 commit 中这个值在所有的 profiler 之间是共享的,可以将它们按需分组。
- interactions: 当更新被制定时,“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 DevTools 控制台,查看下面的时间:
我们还可以打开 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>
);
但是,如果要追踪交互行为怎么办?
交互跟踪API
如果我们可以追踪交互行为(例如单击UI)来回答比如 “单击此按钮需要多长时间才能更新DOM?” 之类的问题,那就太强大了。感谢 Brian Vaughn, React 通过新的调度器包中的交互跟踪API对交互跟踪提供了实验支持。这里有更详细的记录。
交互带有一个注释(例如“单击添加到购物车按钮”)和一个时间戳。还应该为交互提供一个回调函数,你可以在其中执行与交互相关的工作。
在电影APP中,有一个 “将电影添加到队列” 按钮( )。单击此交互将电影添加到你的观看队列:
以下是此交互的跟踪状态更新的示例:
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 DevTools 中看到它的持续时间:
也可以使用交互跟踪API跟踪首次渲染,如下所示:
import { unstable_trace as trace } from "scheduler/tracing";
trace("initial render", performance.now(), () => {
ReactDom.render(, document.getElementById("app"));
});
Puppeteer
对于 UI 交互的更深入的脚本跟踪,你可能对 Puppeteer 感兴趣。Puppeteer 是一个 Node 库,它提供了一个高级API,用于通过 DevTools 协议控制无头浏览器。
它提供了了 tracing.start()/stop() 这些工具方法,以捕获 DevTools 工作的性能跟踪。下面,我们使用它来跟踪单击主按钮时发生的情况。
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);
// Begin profiling...
await page.tracing.start({ path: \'profile.json\' });
// Click the button
await page.click(addMovieToQueueBtn);
// Stop profliling
await page.tracing.stop();
await browser.close();
})();
将 profile.json 加载到 DevTools Performance 面板中,我们可以通过单击按钮来查看所有由此产生的 JavaScript 函数调用:
User Timing API
通过 User Timing API,可以使用高精度时间戳来测量应用程序的自定义性能指标。window.performance.mark() 存储带有相关名称的时间戳,而 window.performance.measure() 存储两个标记之间经过的时间。
// Record the time before running a task
performance.mark(\'Movies:updateStart\');
// Do some work
// Record the time after running a task
performance.mark(\'Movies:updateEnd\');
// Measure the difference between the start and end of the task
performance.measure(\'moviesRender\', \'Movies:updateStart\', \'Movies:updateEnd\');
当你使用 Chrome DevTools 性能面板配置一个React应用程序时,你会发现一个名为Timings 的部分,里面存储了 React 组件的处理时间。渲染时, React 可以使用 User Timing API 发布此信息。
注意:React从他们的开发包中删除了 User Timing API ,取而代之的是 React Profiler,它提供了更准确的计时。他们可能会在未来的3级浏览器中重新添加它。
在网上,你会发现一些 React 应用利用 User Timing API 来定义自己的自定义指标。其中包括 Reddit 的“显示第一个帖子标题的时间”和 Spotif y的“准备播放的时间”:
自定义用户计时指标也可以方便地反映在 Chrome DevTools 的 Lighthouse 面板中:
Next.js 的最新版本还为许多事件添加了更多的用户计时标记和度量,包括:
- Next.js-hydration
- Next.js-nav-to-render
所有这些度量都显示在 Timing 区域中:
DevTools & Lighthouse
Lighthouse 和 Chrome DevTools Performance 面板可用于深入分析 React 应用程序的负载和运行时性能,突出显示以用户为中心的关键指标:
React 用户可能会喜欢像总阻塞时间(TBT)这样的新指标,它量化了一个页面在变得具有可靠交互性之前的非交互性(变为交互性的时间)。下面我们可以看到一个应用程序的并发模式的TBT之前/之后的TBT,在此更好地分散更新:
这些工具通常有助于获得一个浏览器级别的瓶颈视图,如延迟交互的长时间任务(如按钮点击响应),如下所示:
Lighthouse 还提供了许多为 React 特殊定制的审计:
内容出处:,
声明:本网站所收集的部分公开资料来源于互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。文章链接:http://www.yixao.com/procedure/8856.html