分析 React 组件的渲染性能「实践」
bigegpt 2024-12-28 11:19 3 浏览
作者:ConardLi
转发链接:https://mp.weixin.qq.com/s/tDWBFlZf-rh_IvlSqKTcgg
前言
今天,我们介绍一下如何使用 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 }) => (
<Fragment>
<Profiler id="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(<App />, 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 特殊定制的审计:
推荐React 学习相关文章
《这就是你日思夜想的 React 原生动态加载「值得收藏」》
《手把手教你从Mixin深入到HOC再到Hook【React】》
《深入Facebook 官方React 状态管理器Recoil讲解》
《React源码分析与实现(一):组件的初始化与渲染「实践篇」》
《React源码分析与实现(二):状态、属性更新->setState「实践篇」》
《手把手教你10个案例理解React hooks的渲染逻辑「实践」》
《Vue 3.0 Beta 和React 开发者分别杠上了》
《手把手深入Redux react-redux中间件设计及原理(上)【实践】》
《手把手深入Redux react-redux中间件设计及原理(下)【实践】》
《为了学好 React Hooks, 我解析了 Vue Composition API》
《【React 高级进阶】探索 store 设计、从零实现 react-redux》
《深入浅出掌握React 与 React Native这两个框架》
《你需要的 React + TypeScript 50 条规范和经验》
《手把手教你深入浅出实现Vue3 & React Hooks新UI Modal弹窗》
《全平台(Vue/React/微信小程序)任意角度旋图片裁剪组件》
作者:ConardLi
转发链接:https://mp.weixin.qq.com/s/tDWBFlZf-rh_IvlSqKTcgg
相关推荐
- 了解Linux目录,那你就了解了一半的Linux系统
-
大到公司或者社群再小到个人要利用Linux来开发产品的人实在是多如牛毛,每个人都用自己的标准来配置文件或者设置目录,那么未来的Linux则就是一团乱麻,也对管理造成许多麻烦。后来,就有所谓的FHS(F...
- Linux命令,这些操作要注意!(linux命令?)
-
刚玩Linux的人总觉得自己在演黑客电影,直到手滑输错命令把公司服务器删库,这才发现命令行根本不是随便乱用的,而是“生死簿”。今天直接上干货,告诉你哪些命令用好了封神!喜欢的一键三连,谢谢观众老爷!!...
- Linux 命令速查手册:这 30 个高频指令,拯救 90% 的运维小白!
-
在Linux系统的世界里,命令行是强大的武器。对于运维小白而言,掌握一些高频使用的Linux命令,能极大提升工作效率,轻松应对各种系统管理任务。今天,就为大家奉上精心整理的30个Linu...
- linux必学的60个命令(linux必学的20个命令)
-
以下是Linux必学的20个基础命令:1.cd:切换目录2.ls:列出文件和目录3.mkdir:创建目录4.rm:删除文件或目录5.cp:复制文件或目录6.mv:移动/重命名文件或目录7....
- 提高工作效率的--Linux常用命令,能够决解95%以上的问题
-
点击上方关注,第一时间接受干货转发,点赞,收藏,不如一次关注评论区第一条注意查看回复:Linux命令获取linux常用命令大全pdf+Linux命令行大全pdf为什么要学习Linux命令?1、因为Li...
- 15 个实用 Linux 命令(linux命令用法及举例)
-
Linux命令行是系统管理员、开发者和技术爱好者的强大工具。掌握实用命令不仅能提高效率,还能解锁Linux系统的无限潜力,本文将深入介绍15个实用Linux命令。ls-列出目录内容l...
- Linux 常用命令集合(linux常用命令全集)
-
系统信息arch显示机器的处理器架构(1)uname-m显示机器的处理器架构(2)uname-r显示正在使用的内核版本dmidecode-q显示硬件系统部件-(SMBIOS/DM...
- Linux的常用命令就是记不住,怎么办?
-
1.帮助命令1.1help命令#语法格式:命令--help#作用:查看某个命令的帮助信息#示例:#ls--help查看ls命令的帮助信息#netst...
- Linux常用文件操作命令(linux常用文件操作命令有哪些)
-
ls命令在Linux维护工作中,经常使用ls这个命令,这是最基本的命令,来写几条常用的ls命令。先来查看一下使用的ls版本#ls--versionls(GNUcoreutils)8.4...
- Linux 常用命令(linux常用命令)
-
日志排查类操作命令查看日志cat/var/log/messages、tail-fxxx.log搜索关键词grep"error"xxx.log多条件过滤`grep-E...
- 简单粗暴收藏版:Linux常用命令大汇总
-
号主:老杨丨11年资深网络工程师,更多网工提升干货,请关注公众号:网络工程师俱乐部下午好,我的网工朋友在Linux系统中,命令行界面(CLI)是管理员和开发人员最常用的工具之一。通过命令行,用户可...
- 「Linux」linux常用基本命令(linux常用基本命令和用法)
-
Linux中许多常用命令是必须掌握的,这里将我学linux入门时学的一些常用的基本命令分享给大家一下,希望可以帮助你们。总结送免费学习资料(包含视频、技术学习路线图谱、文档等)1、显示日期的指令:d...
- Linux的常用命令就是记不住,怎么办?于是推出了这套教程
-
1.帮助命令1.1help命令#语法格式:命令--help#作用:查看某个命令的帮助信息#示例:#ls--help查看ls命令的帮助信息#netst...
- Linux的30个常用命令汇总,运维大神必掌握技能!
-
以下是Linux系统中最常用的30个命令,精简版覆盖日常操作核心需求,适合快速掌握:一、文件/目录操作1.`ls`-列出目录内容`ls-l`(详细信息)|`ls-a`(显示隐藏文件)...
- Linux/Unix 系统中非常常用的命令
-
Linux/Unix系统中非常常用的命令,它们是进行文件操作、文本处理、权限管理等任务的基础。下面是对这些命令的简要说明:**文件操作类:*****`ls`(list):**列出目录内容,显...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- logstashinput (65)
- hadoop端口 (65)
- vue阻止冒泡 (67)
- oracle时间戳转换日期 (64)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)