React 16.5 添加了对新的 profiler DevTools 插件的支持。这个插件使用 React 的 Profiler 实验性 API 去收集所有 component 的渲染时间,目的是为了找出你的 React App 的性能瓶颈。它将会和我们即将发布的 时间片 特性完全兼容。

Profile 一个 APP

DevTools 将会对支持新的 profiling API 的 APP 新加一个 “Profiler” tab 列:


react record 怎么用 react profiler_react record 怎么用

这个 “Profiler” 的面板在刚开始的时候是空的。你可以点击 record 按钮来启动 profile:

react record 怎么用 react profiler_python_02

当你开始记录之后,DevTools 将会自动收集你 APP 在(启动之后)每一刻的性能数据。(在记录期间)你可以和平常一样使用你的 APP,当你完成 profile 之后,请点 “Stop” 按钮。

react record 怎么用 react profiler_python_03

如果你的 APP 在 profile 期间重新渲染了几次,DevTools 将会提供好几种方法去查看性能数据。我们将会 在接下来讨论它们。

查看性能数据

浏览 commits

从概念上讲,React 的运行分为两个阶段:

  • 在 render 阶段会确定例如 DOM 之类的数据需要做那些变化。在这个阶段,React 将会执行(各个组件的)render 方法,之后会计算出和调用 render 方法之前有哪些变化。
  • commit 阶段是 React 提交任何更改所在的阶段(在 React DOM 下,就是指 React 添加、修改和移除 DOM 节点的时候)。同时在这个阶段,React 会执行像 componentDidMount 和 componentDidUpdate 这类周期函数。

profiler DevTools 是在 commit 阶段收集性能数据的。各次 commit 会被展示在界面顶部的条形图中:

react record 怎么用 react profiler_python_04

在条形图中,每一列都表示单次的 commit 数据,你当前选中的 commit 列会变成黑色。你可以点击各个列(或者是左/右切换按钮)来查看不同的 commit 数据。

这些列的颜色和高度对应着该次 commit 在渲染上所花的时间(较高、偏黄的列会比较矮、偏蓝的列花费的时间多)。

筛选 commits

你 profile 的记录时间越长,渲染次数就会越多。有时候你或许会被过多的(价值低的)commit 记录干扰。为了帮助你解决这个问题,profiler 提供了一个筛选功能。用它来制定一个时间阀值,之后 profiler 会隐藏所有比这个阀值更快的 commit。


react record 怎么用 react profiler_react record 怎么用_05

火焰图

(译者注:阮一峰:如何读懂火焰图?)

火焰图会展示你所指定的那一次 commit 的信息。图中每一列都代表了一个 React component(例如下图中的 App、Nav)。各列的尺寸和颜色表示这列所代表的 component 及其 children 的渲染时间(列的宽度表示该 component 最近一次渲染所花费的时间,列的颜色代表在该次 commit 中渲染所花费的时间)。


react record 怎么用 react profiler_python_06

Note:

列的宽度表示 component(和它的 children)最近一次渲染所花费的时间。如果这个 component 在本次 commit 中没有被重新渲染,那其所展示的时间表示上一次 render 的耗时。一个列越宽,其所代表的 component 渲染耗时就越长。

列的颜色表示在本次 commit 中该 component(和它的 children)所花费的时间。黄色代表耗时较长、蓝色代表耗时较短,灰色代表该 component 在这次 commit 中没有被(重新)渲染。

举个例子,上图中所展示的 commit 总共渲染耗时为 18.4 ms。Router component 是渲染成本“最昂贵”的 component(花费了 18.4 ms)。他所花费的时间大部分在两个 children 上:Nav(8.4 ms)和 Route (7.9 ms)。剩下的时间用于它的其他 children 和它自身的渲染。

你可以通过点击 component 列来放大或缩小火焰图:

react record 怎么用 react profiler_java_07

点击一个 component 的同时也会选中它,它的具体信息将会展示在右边的数据列,列里会展示该 component 在这次 commit 时的 props 和 state。你可以去深入研究这些数据来找出这次 commit 具体做了哪些。

react record 怎么用 react profiler_python_08

某些情况下,选中一个 component 后在不同的 commit 之间切换也可以发现触发这次渲染的原因:

react record 怎么用 react profiler_react record 怎么用_09

上图表示在两次 commit 中 state.scrollOffset 被改变了。这或许就是触发 List component 重绘的原因。

排序图

同火焰图一样,排序图也会展示你所指定的那一次 commit 的信息,图中每一列都代表了一个 React component(例如下图中的 App、Nav)。不同的是排序图是有顺序的,耗时最长的 component 会展示在第一行。

react record 怎么用 react profiler_react_10

Note:

一个 component 的渲染时间也包括了它的 children 们消耗的时间,所以渲染耗时最长的 component 通常距离树顶部最近。

和火焰图一样,你可以通过点击 component 列来放大或缩小排序图(译者注:排序图只会展示在本次 commit 中被触发重绘的 component)。

Component 图

在你 profile 的过程中,使用该图查看单一 component(在多次 commit 中)的渲染时间有时候是非常有用的。Component 图会以一个列的形式展示,其中每一列都表示你所选择的 component 的某一次 commit 下的渲染时间。每列高度和颜色都表示该 component 在某次 commit 中同其它组件的耗时对比。

react record 怎么用 react profiler_面试_11

上图表明 List component 渲染了 11 次。同时还表明 List 在每次渲染中是最“昂贵”的组件。(译者注:此处是通过列的颜色判断)查看这种图的方法有两种:双击一个 component 或者是选中一个 component 后点击在右边列中的蓝色表格按钮。你可以通过点击右边列的 “x” 按钮来返回原图,当然你也可以双击 Component 图中的某一列来查看那次 commit 的更多信息。

react record 怎么用 react profiler_面试_12

如果你所选中的 component 在 profile 期间从来没被渲染过,则会显示下面的信息:

react record 怎么用 react profiler_react_13

交互动作(Interactions)

React 最近添加了一个 实验性 API,目的是为了追踪引起更新的原因。被这些API所追踪的“交互动作”也会展示在 profiler 里:

react record 怎么用 react profiler_react_14

上图展现了一个 profile 期间被追踪的 4 个交互动作。每行都展示了一个追踪的交互动作。每行里带有颜色的点表示与其交互动作所对应的 commit 记录。你也可以在特定的 commit 记录的右边列看到在该记录期间所被追踪的交互动作。

react record 怎么用 react profiler_面试_15

你可以通过点击它们来实现在交互动作和 commits 之间的跳转:

react record 怎么用 react profiler_react_16

tracking API 仍然是很新的特性,我们会在接下来的博客文章中详细介绍它。

常见问题 & 解决方法

选择的根元素下没有 profile 数据被记录

如果你的 APP 有好几个 “root”(译者注:指 React 有好几个 root 组件),你可能会在 profile 之后看到下面的信息:

react record 怎么用 react profiler_面试_17

这个信息表示你在 “Elements” 界面下所选择的 root 之下没有性能数据被记录。这种情况下,请尝试选择一个不同的根元素来查看在这个 root 下的 profile 数据:

react record 怎么用 react profiler_python_18

选中的 commit 记录没有时间数据可以展示

有时候 commit 速度可能非常地快,以至于 performance.now() 没法提供给 DevTools 任何有意义的数据。这种情况下,会展示下面的界面:

react record 怎么用 react profiler_react record 怎么用_19