原文地址:High Performance React: 3 New Tools to Speed Up Your Apps
文中介绍了几种 React 应用性能检测工具,并且提供了几条关于应用性能提升的解决方案。

React 通常都是非常快的,只不过一些小错误很容易会导致性能问题,组件挂载慢、组件树过深以及无意义的渲染周期等因素都会导致用户使用时感觉很慢。

工具#1:Chrome 的 Performance 时间轴

React 15.4 引入了一个新的 Performance 时间轴功能,它可以让你准确查看组件的挂载、更新以及卸载的过程,还能可视化相关组件的生命周期。
注意:因为该功能使用了尚未完全适配的 User Timing API,所以目前只适用于 Chrome、Edge、以及 IE。

如何使用

  1. 在 Chrome 中访问你的页面,并且在 URL 后添加一个参数:react_perf,例如://localhost:3000?react_perf
  2. 打开 Chrome 调试面板,进入 Performance 选项,点击 Record
  3. 执行一些你想分析的操作
  4. 停止 Recording
  5. 检查时间轴中生成的可视化图表

查看检测结果

每个彩条代表着一个组件占用的时间,因为 Javascript 是单线程的,当一个组件正在挂载或渲染时,它会占用主进程并且会阻止其他代码运行。

[update] 一类被包在括号中的文字描述了组件当前的状态,即组件正处于生命周期的哪一阶段。时间轴会分解出每个过程,因此你可以看到类似于 [componentDidMount][componentWillReceiveProps][ctor] (构造函数)、以及 [render] 等方法占用的时间。

堆叠到一起的彩条代表组建树,虽然在 React 中经常见到非常深的组件树,但如果你优化一些频繁挂载的组件,则可以减少包装组件的数量,而每少一个组件都会减少性能以及内存的损耗。

这里需要注意的是,时间轴中展示的消耗时间是 React 开发环境编译的效果,会比生产环境慢很多。事实上, 使用 Performance 时间轴本身也会拖慢页面的速度。虽然这些时间不能代表页面在实际生产环境中的表现,但不同组件之间的相对时间是准确的,此外,组件是否更新与页面是否是处于生产环境,这两者之间也无关联。

示例#1

为了例子生动好玩,我在 TodoMVC 项目中恶意制造了一些严重的性能问题,你可以在这里试试
在页面中打开调试工具,在 Performance 选项中点选 Record,然后可以在页面添加一些 TODO,停止 Record,检查时间轴,看看你能不能定位页面中造成性能问题的组件 :)。

工具#2:why-did-you-update

无意义的渲染周期是造成 React 性能问题的最常见的原因之一,React 默认状态下,如果父组件渲染,子组件即便属性值没有改变也会重新渲染。
举个例子,现有子组件如下:

class DumbComponent extends Component {
      render() {
    return <div> {this.props.value} </div>;
      }
}

父组件如下所示:

class Parent extends Component {
      render() {
          return <div>
              <DumbComponent value={3} />
          </div>;
      }
}

不管父组件什么时候渲染,DumbComponent 都会重新渲染,不管它的属性值有没有改变。

通常,如果 render 函数执行了,但虚拟 DOM 没有任何改变,就意味此渲染周期是浪费的,无意义的,render 方法应该是纯净并且没有任何副作用的,在庞大的 React 项目中,要检测可能造成这些问题的代码会非常棘手,但比较方便的是,现在有个现成的工具可以用。

使用 why-did-you-update

why-did-you-update 是一个挂钩到 React 的库,可以检测一些潜在的不必要的组件渲染,它可以检测到组件属性值没变但却重新渲染的情况。

设置

  1. 用 npm 安装:npm i --save-dev why-did-you-update
  2. 把下面这段代码放到页面中,位置不限:
    import React from 'react'
    if (process.env.NODE\_ENV !== 'production') {
          const {whyDidYouUpdate} = require('why-did-you-update')
          whyDidYouUpdate(React)
    }
    

注意: why-did-you-update 虽然在开发环境下非常好用,但是一定要确保在上线前注释或删除这段代码,否则它会拖慢页面速度。

查看检测结果

当项目运行时,why-did-you-update 监控页面并且打印出没必要改变的组件,并展示这些组件渲染周期前后的属性值。

示例#2

为了演示,我在 TodoMVC 项目里安装了 why-did-you-update,并放在了 Code Sandbox 平台上(一个线上 React 平台),打开浏览器的 console,在页面中添加一些 ToDo,你就会看到控制台输出的问题。

这里是项目

需要注意的是,项目中的一些组件存在无意义渲染,试试上面的方式来杜绝那些无意义的组件渲染,如果你处理正确的话,控制台中应该没有 why-did-you-update 输出的警告。

React 开发工具

Chrome 扩展“React Developer Tools”已经内建了更新组件的高亮功能,这对于定位无意义的组件渲染是非常有用的,要使用功能,首先得安装 React Developer Tools 扩展
安装后,在调试面板中进入 React 选项狂,打开 “Highlight Updates” 功能。

然后操作项目页面,和不同的组件进行交互,你就可以看到 React 开发工具高亮的效果了。

查看检测结果

React 开发工具高亮显示了那些在给定时间内重新渲染的组件,不同颜色的高亮对应了组件更新的频率,蓝色代表更新频率低,而颜色范围为绿黄红则代表了高频更新。
看到黄色或者红色不一定代表有问题,可能是调整滑动条或触发频繁更新的其他 UI 组件。但如果你点击了一个按钮却看到了红色高亮,这可能代表代码有问题了。该扩展的功能是让开发者定位项目中无意义更新的组件,作为一个开发者,你应该对给定时间内哪些组件需要更新有大概的意识。

示例#3

同上面的例子一样,为了演示更形象生动,我在 TodoMVC 项目中恶意造成了一些不必要的组件更新。
TodoMVC 项目地址
打开上面的项目链接,打开 React 开发工具,并且打开 “update highlighting”,当你在输入框中输入时,你会看到所有的 Todo 条目都在高亮,如果你快速输入,你会看到高亮的颜色不同,分别代表着这些组件的更新频率。

修复无意义渲染

当你确定项目中的一些组件存在无意义渲染的情况时,有以下几种简单的修复方式。

使用 PureComponent

在上面的示例中,DumbComponent 想对于它的属性值是一个纯粹的函数,也就是说,该组件只需要在它的属性值改变时进行重新渲染,React 有一个内建的特殊组件 PureComponent 恰好适用于这种场景。
现用 React.PureComponent 取代 React.Component,如下所示:

class DumbComponent extends PureComponent {
      render() {
        return <div> {this.props.value} </div>;
      }
}

使用以上的写法,该组件就只会在属性值改变的情况下重新渲染。

需要注意的是,PureComponent 对属性值只做了浅比较,如果数据结构比较复杂,它可能会忽略一些属性的属性的改变而不让组件重新渲染。

执行 shouldComponentUpdate

shouldComponentUpdate 是一个组件因为属性或者状态改变而重新渲染之前被调用的组件方法,如果 shouldComponentUpdate 返回 truerender 会被调用,如果返回的是 false, render 则不会被调用。
通过执行 shouldComponentUpdate 方法,你可以避免无意义的组件渲染。
举个例子,现在 dumb 组件中添加 shouldComponentUpdate 方法,像以下展示的写法:

class DumbComponent extends Component {
     shouldComponentUpdate(nextProps) {
    if (this.props.value !== nextProps.value) {
          return true;
    } else {
          return false;
    }
      }
    render() {
    return <div>foo</div>;
      }
}

在生产环境调试性能问题

React 开发工具只在你本地起作用,但如果你想在生产环境了解项目的性能问题的话,你应该试试 LogRocket

LogRocket 就像是网络应用的录像机,记录在你网站上发生的一切,你不用去猜测问题的原因,你可以重播存在 bug 或者性能问题的会话来快速定位问题的根本原因。
LogRocket 会记录页面的性能数据、Redux 动作/状态、日志、错误、网络请求/响应(包含响应头和响应体)以及浏览器的 metadata。也会记录页面中的 HTML 和 CSS,重新创建即使是最复杂的单页应用的非常完美的视频。

LogRocket | Logging and Session Replay for JavaScript Apps

感谢您的阅读,希望这些工具和技巧对你的下一个项目会有帮助!