阿里、蚂蚁、晟腾、中科加禾精彩分享 AI 基础设施洞见,现购票可享受 9 折优惠 |AICon 了解详情
写点什么

React.js 性能分析

  • 2020-04-27
  • 本文字数:3300 字

    阅读完需:约 11 分钟

React.js性能分析

今天我将向大家演示如何使用 React Profiler APITracing API 以及 User Timing API 来分别追踪 React 的组件渲染、用户交互以及自定义性能指标。


本文最初发布于Addy Osmani博客,经原作者授权由 InfoQ 中文站翻译并分享。


下面我会用一个影片排期的应用做具体的演示(译者注:应用效果图如下)。


React Profiler API

首先来了解下React Profiler,它主要用来追踪应用组件的渲染过程以及渲染开销,同时标记出应用的性能瓶颈。Profiler 接受一个 onRender 回调函数,当被追踪的组件以及子代组件发生更新时,该函数就会被调用。下图是在影片排期应用中使用 Profiler 追踪各个组件渲染:



Profiler 中 onRender 回调函数的具体参数如下:


  • id:这是 Profiler 的唯一标示,区分是哪个 Profiler 追踪的组件树发生了更新

  • phase:如果更新是挂载阶段这个值就是“mount”,如果是二次渲染阶段就是“update”

  • actualDuration:更新花费的渲染时间

  • 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 同样也可以追踪初始化渲染


import { unstable_trace as trace } from "scheduler/tracing";trace("initial render", performance.now(), () => {   ReactDom.render(<App />, document.getElementById("app"));})
复制代码



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 应用已经在使用 User Timing 追踪他们的自定义指标,包括 Reddit 网站中的“到第一标题可见花费的时间”和 Spotify 网站中的“到回放准备完毕花费的时间”。



还可以在 Chrome 调试器的Lighthouse面板中查看到定制化的User Timing标记和追踪方法,如下图:



Next.js的最近版本中也针对一些事件添加了很多 User timing 标记和追踪,例如:


  • Next.js-hydration:混合持续时间

  • Next.js-nav-to-render:导航开始到开始渲染之间的时间


所有的这些追踪都可以在调试器的 Timings 区域看到:


对比 DevTools 和 Lighthouse

值得注意的是,LighthouseChrome调试工具中的性能面板都可以深入分析 React 应用程序的加载和运行时性能,用户可以看到下面这些性能指标:



React 用户可能会喜欢像总阻塞时间(TBT)这样的新指标,它量化一个页面具体什么时候才可以交互(可交互时间), 下面我们可以看下在并发模式前后应用发生更新时,TBT 的情况:



这些工具一般能帮助我们了解在浏览器级别的视图性能瓶颈,例如,哪些繁重冗长的任务会引起交互延迟(例如按钮点击响应) :



Lighthouse 还为一些特定的性能场景提供了修改建议。如在Lighthouse 6.0中可以看到一个提示,建议我们移除未使用的JavaScript代码。Lighthouse 追踪到了这个问题并且提醒我们可以使用 React.lazy ()来引入这个 JavaScript。



借助用户端的硬件进行性能智能检查,往往对性能分析非常有帮助。


最后,除了上面提到的我通常还会从RUM 和 CrUX获取一些数据字段,然后用webpagetest.org/easy工具帮我生成更多的场景图片,以便更好的进行性能分析。

更多文章


如果你对文章中的 demo 有兴趣,可以点击查看在线demo,或者从Glitch上下载源码。


原文链接:Profiling React.js Performance


2020-04-27 12:122755

评论 1 条评论

发布
暂无评论
发现更多内容

字节跳动有状态应用云原生实践

火山引擎开发者社区

云原生 后端

开源即巅峰!阿里首次分享:Java架构师全栈“成长笔记”

Java架构师迁哥

区块链时代下,企业如何打造数据要素的“新竞争力”?

旺链科技

大数据 产业区块链

Java项目实战营总结

eoeoeo

手机如果能折叠能卷的话,电脑为什么不能呢?

船医特拉法尔加

开发者 工具 柔性屏

阿里的架构师一致好评!IT界首版全栈架构师全栈“成长笔记”开源!

Java架构追梦

Java 阿里巴巴 架构 面试 成长笔记

这套获50w+星标的算法神仙文档,足你解决90%的对手,牛逼

编程 程序员 架构 面试

腾讯上线零点巡航,用Java手撕一个人脸识别系统

北游学Java

Java 腾讯 人脸识别

部分简单网页的基础了解

Emotion

html html5 Html报文解析 内部样式、 CSS语法

CDH 安装搭建(二)

大数据技术指南

CDH 7月日更

云图说|应用魔方AppCube:揭秘码农防脱神器

华为云开发者联盟

低代码 华为云 AppCube 云图说 应用魔方

云端赛车-Amazon DeepRacer 的前世今生

亚马逊云科技 (Amazon Web Services)

人工智能 开源

监测生命体征、活动水平的可穿戴电子产品设计方案

不脱发的程序猿

物联网 ADI 可穿戴电子产品设计方案 监测生命体征、活动水平 智能传感器

渗透工程师必看-网络安全法条例-国家安全法介绍和案例

学神来啦

运维 黑客 安全 渗透

Go 学习笔记之 字符串数据类型

架构精进之路

Go 语言 7月日更

对EF Core进行扩展使支持批量操作/复杂查询

Spook

EF Core

卧薪尝胆30天!啃透京东大牛的高并发设计进阶手册,终获P7意向书

Java 编程 程序员 架构 面试

linux网络编程—7层网络以及5种Linux IO模型以及相应IO基础

Linux服务器开发

后端 网络编程 Linux服务器开发 网络模型 IO模型

QuFi挖矿APP开发|QuFi挖矿系统软件开发

记某百亿级mongodb集群数据过期性能优化实践

杨亚洲(专注MongoDB及高性能中间件)

Java MySQL 数据库 mongodb 分布式数据库mongodb

云原生打包工具:Buildpacks

QiLab

Docker 云原生 k8s buildpacks

程序员如何提高开发效率?

万事ONES

项目管理 程序员 敏捷开发 ONES

共36万字!为上岸Alibaba,我把Github上Java面试题都整理了一遍

Java 编程 程序员 架构 面试

银行4.0时代的营销与风控之路

索信达控股

大数据 金融科技 数字化转型 银行数字化转型 营销数字化

爱了!阿里巴巴 Java 面试参考权威指南(泰山版)5月版开源

Java 编程 程序员 架构 面试

MySQL连接数管理

Simon

MySQL

Hive学习笔记(一)

五分钟学大数据

hive 7月日更

JAVA 九种排序算法详解(下)

加百利

Java 数组 排序 7月日更

手把手教你实现聚光灯效果

ThingJS数字孪生引擎

大前端 可视化 智能灯控 数字孪生

数据归档 - 冷热数据处理大师

趣链科技

数据处理 区块链+

mPaaS 月度小报 | CodeDay#6 成都站落幕,下一站北京;上新季:新容器、新官网、新视觉

蚂蚁集团移动开发平台 mPaaS

移动开发 mPaaS

React.js性能分析_语言 & 开发_Addy Osmani_InfoQ精选文章