内容简介:在数据中台做 BI 工具经常面对海量数据的渲染处理,除了组件本身性能优化之外,经常要排查整体页面性能瓶颈点,尤其是维护一些性能做得并不好的旧代码时。React 性能调试是面对这种问题的必修课,借助本文介绍了众多性能检测工具与方法。
1 引言
在数据中台做 BI 工具经常面对海量数据的渲染处理,除了组件本身性能优化之外,经常要排查整体页面性能瓶颈点,尤其是维护一些性能做得并不好的旧代码时。
React 性能调试是面对这种问题的必修课,借助 Profiling React.js Performance 这篇文章一起学习一下这个技能吧。
2 精读
本文介绍了众多性能检测 工具 与方法。
React Profiler
Profiler
这个 API 是一种运行时 Debug 的补充,可以通过其 callback 拿到组件渲染信息,用法如下:
const Movies = ({ movies, addToQueue }) => ( <React.Profiler id="Movies" onRender={callback}> <div /> </React.Profiler> ); function callback( id, phase, actualTime, baseTime, startTime, commitTime, interactions ) {}
这个 callback 会在每次渲染时执行,渲染分为初始化和更新阶段,通过 phase
区分,下面是参数详细说明:
setState
注意尽量不要轻易使用 Profiler
检测性能,因为 Profiler
本身也会消耗性能。
如果不想获得这么详细的渲染耗时,或者不想提前在代码中埋点,可以利用 DevTools 的 Profiler 查看更直观更简洁的渲染耗时:
其中 Ranked 可以展示按照渲染耗时 排序 后的结果,Interations 需要配合 Tracing API 使用,在后面会提到。
Tracing API
利用 scheduler/tracing
提供的 trace
API,我们可以记录某个动作的耗时,比如 “点击添加按钮收藏一个电影” 耗时多久:
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 }); }); }; }
在 Interations 中可以看到动作触发的耗时:
这个动作还可以是渲染,比如可以记录 ReactDOM 渲染的耗时:
import { unstable_trace as trace } from "scheduler/tracing"; trace("initial render", performance.now(), () => { ReactDom.render(<App />, document.getElementById("app")); });
甚至还可以追踪异步的耗时:
import { unstable_trace as trace, unstable_wrap as wrap, } from "scheduler/tracing"; trace("Some event", performance.now(), () => { setTimeout( wrap(() => { // 异步操作 }) ); });
有了 Profiler
与 trace
这两件武器,我们可以监控任意元素的渲染耗时与交互耗时,几乎可以涵盖所有性能监控需要。
Puppeteer
我们还可以利用 Puppeteer 实现自动化操作并打印报告:
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(); })();
首先利用 puppeteer
创建一个浏览器,新建一个页面并打开 https://react-movies-queue.glitch.me/
这个 URL,等待页面加载完毕后利用 DOM 选择器找到按钮,利用 page.click
API 模拟点击这个按钮,并在前后利用 page.tracing
记录性能变化,并将这个文件上传到 DevTools Performance 面板,就会得到一份自动的性能检测报告:
这张图相当重要,是浏览器综合运行开销分析的利器,最上面分为 4 个部分:
- FPS:每秒帧数,绿色竖线越高表示 FPS 越高,出现红线则表示出现了卡顿。
- CPU:CPU 资源,用面积图展示消耗 CPU 资源的事件。
- NET:网络消耗,每条横杠表示一种资源的加载。
- HEAP:内存水位,由于短时间内看不出来是否会内存溢出,一般只用来简单看看内存消耗是否符合预期,对于内存溢出的检测需要用持续监控上报的方式。
下面会有一张 Network 详细图解,比如这张图:
细线表示等待的时间,粗线表示实际加载的情况,其中浅色部分表示服务器等待时间,即从发送下载请求到服务器响应第一个字节的时间。这部分可以看出资源并行加载阻塞情况以及资源服务器响应时间是否存在问题。
Timings 展示了几个重要时间节点,这里列举一部分:
- FP:First Paint,第一次绘制。
- FCP:First Contentful Paint,第一次内容绘制。
- LCP:Largest Contentful Paint,最大内容绘制。
- DCL:Document Content Loaded,DOM 内容加载完毕。
再下面是 JS 计算消耗,用了一张火焰图,火焰图是性能分析的常用可视化工具。以下面这张图为例:
看火焰图首先看跨度最长的函数,也就是最长的那条线,这是最耗时的部分,从左到右是浏览器脚本的调用顺序,从上到下是函数嵌套的顺序。
我们可以看到鼠标位置的 34 这个函数虽然长,但并不是性能瓶颈,因为下面执行的 n 函数长度和它一样,表示 34 函数的性能几乎无损耗,其性能由其调用的 n 函数决定。
我们可以利用这种方式一步步排查到叶子结点,找到对性能影响最大的元子函数。
User Timing API
我们还可以利用 performance.mark
自定义性能检测节点:
// 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");
这些节点可以在上面介绍的 Performance 面板中展示出来用于自定义分析。
3 总结
利用 Performance 进行通用性能分析,利用 React Profiler 进行 React 定制性能分析,这两个结合在一起几乎可以完成任何性能检测。
一般来说,首先应该用 React Profiler 进行 React 层面的问题筛查,这样更直观,更容易定位问题。如果某些问题跳出了 React 框架范围,或者不再能以组件粒度进行度量,我们可以回到 Performance 面板进行通用性能分析。
讨论地址是: 精读《React 性能调试》 · Issue #247 · dt-fe/weekly
如果你想参与讨论,请 点击这里 ,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。
关注 前端精读微信公众号
版权声明:自由转载-非商用-非衍生-保持署名( 创意共享 3.0 许可证 )
以上所述就是小编给大家介绍的《精读《React 性能调试》》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 精读《Typescript 4》
- 精读《正则 ES2018》
- AIStats 2017文章精读(四)
- 精读《如何比较 Object 对象》
- 精读《谈谈 Web Workers》
- 精读《React PowerPlug 源码》
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
第一本Docker书 修订版
詹姆斯·特恩布尔 (James Turnbull) / 李兆海、刘斌、巨震 / 人民邮电出版社 / 2016-4-1 / CNY 59.00
Docker是一个开源的应用容器引擎,开发者可以利用Docker打包自己的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。 本书由Docker公司前服务与支持副总裁James Turnbull编写,是Docker开发指南。本书专注于Docker 1.9及以上版本,指导读者完成Docker的安装、部署、管理和扩展,带领读者经历从测试到生产的整个开发生......一起来看看 《第一本Docker书 修订版》 这本书的介绍吧!