精读《React 性能调试》

栏目: IT技术 · 发布时间: 3年前

内容简介:在数据中台做 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 查看更直观更简洁的渲染耗时:

精读《React 性能调试》

其中 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 中可以看到动作触发的耗时:

精读《React 性能调试》

这个动作还可以是渲染,比如可以记录 ReactDOM 渲染的耗时:

import { unstable_trace as trace } from "scheduler/tracing";

trace("initial render", performance.now(), () => {
  ReactDom.render(<App />, document.getElementById("app"));
});

精读《React 性能调试》

甚至还可以追踪异步的耗时:

import {
  unstable_trace as trace,
  unstable_wrap as wrap,
} from "scheduler/tracing";

trace("Some event", performance.now(), () => {
  setTimeout(
    wrap(() => {
      // 异步操作
    })
  );
});

有了 Profilertrace 这两件武器,我们可以监控任意元素的渲染耗时与交互耗时,几乎可以涵盖所有性能监控需要。

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 面板,就会得到一份自动的性能检测报告:

精读《React 性能调试》

这张图相当重要,是浏览器综合运行开销分析的利器,最上面分为 4 个部分:

  • FPS:每秒帧数,绿色竖线越高表示 FPS 越高,出现红线则表示出现了卡顿。
  • CPU:CPU 资源,用面积图展示消耗 CPU 资源的事件。
  • NET:网络消耗,每条横杠表示一种资源的加载。
  • HEAP:内存水位,由于短时间内看不出来是否会内存溢出,一般只用来简单看看内存消耗是否符合预期,对于内存溢出的检测需要用持续监控上报的方式。

下面会有一张 Network 详细图解,比如这张图:

精读《React 性能调试》

细线表示等待的时间,粗线表示实际加载的情况,其中浅色部分表示服务器等待时间,即从发送下载请求到服务器响应第一个字节的时间。这部分可以看出资源并行加载阻塞情况以及资源服务器响应时间是否存在问题。

Timings 展示了几个重要时间节点,这里列举一部分:

  • FP:First Paint,第一次绘制。
  • FCP:First Contentful Paint,第一次内容绘制。
  • LCP:Largest Contentful Paint,最大内容绘制。
  • DCL:Document Content Loaded,DOM 内容加载完毕。

再下面是 JS 计算消耗,用了一张火焰图,火焰图是性能分析的常用可视化工具。以下面这张图为例:

精读《React 性能调试》

看火焰图首先看跨度最长的函数,也就是最长的那条线,这是最耗时的部分,从左到右是浏览器脚本的调用顺序,从上到下是函数嵌套的顺序。

我们可以看到鼠标位置的 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

如果你想参与讨论,请 点击这里 ,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。

关注 前端精读微信公众号

精读《React 性能调试》

版权声明:自由转载-非商用-非衍生-保持署名( 创意共享 3.0 许可证


以上所述就是小编给大家介绍的《精读《React 性能调试》》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Microsoft.NET框架程序设计

Microsoft.NET框架程序设计

Jeffrey Richter / 李建忠 / 清华大学出版社 / 2003-11 / 68.00元

《Microsoft.NET框架程序设计》(修订版)是《微软.NET程序员系列》丛书之一,主要介绍如何开发面向Microsoft.NET框架的各种应用程序。Microsoft.NET框架是微软公司推出的新平台,包含通用语言运行时(CLR)和.NET框架类库(FCL)。《Microsoft.NET框架程序设计》(修订版)将深入解释CLR的工作机制及其提供的各种构造,同时还将讨论FCL中一些重要的类型......一起来看看 《Microsoft.NET框架程序设计》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具