查看原文
其他

高性能 React: 3 个提升 APP 速度的新工具

2017-07-25 OSC-协作翻译 开源中国

点击图片报名参加广州&珠海源创会


React 已经比较快了,但使用时仍很容易犯些小错误,导致其性能下降。组件挂载慢,组件树层级过深以及没必要的循环渲染都会让app感觉很慢。

幸亏有很多工具(有些甚至内置在 React 中)能帮助诊断性能问题。在这篇文章中,我将告诉你快速生成 React 应用程序的工具和技术。每个部分会有一个互动以及(希望是)有趣的演示!


工具1:The Performance Timeline



React 15.4.0 介绍了一种新的性能 timeline 特性可以让你看到组件安装、更新和卸载的时间,你还可以看到相关可视化组件的生命周期。

注:现在,该功能只适用于Chrome,Edge 和 IE,因为它实用的 User Timing API 尚未在所有浏览器上实现。

如何运行:

  1. 打开你的 app 并附加查询参数: react_perf。例如,http://localhost:3000?react_perf

  2. 打开 Chrome DevTools 的 Performance,点击 Record.

  3. 执行要分析的操作。

  4. 停止记录。

  5. 检查  User Timing.

理解输出的内容

每个颜色栏显示一个组件“工作”的时间。因为JavaScript是单线程的,当一个组件安装或渲染,都会占用主线程并防止其他代码运行。

括号内是 [update]  描述的是组件生命周期的哪一部分正在执行。timeline会把每个步骤分解,所以你可以区分出诸如[componentDidMount][componentWillReceiveProps][ctor](constructor) 和[render]的细微的时间差。

堆叠的条表示组件树。虽然在 React 中有相当深的组件树是典型的,但是如果您正在优化频繁安装的组件,它可以帮助减少包装器组件的数量,因为每个组件都有增加一点性能和内存的损耗。

这里需要注意的一点是,timeline中的数值是用于React开发构建的,所以相对于生产会慢许多。事实上,使用timeline也会使你的app变慢。虽然这些数值并不代表真实环境的性能,但是不同组件的相对时间是精确的。而且,组件是否更新并不取决于生产环境。

这里需要注意的一点是,timeline中的数值是用于React开发构建的,所以用于实际生产时会感觉比较慢。事实上,使用 timeline 也会使你的 app 变慢。虽然这些数值并不代表真实环境的性能,但是不同组件的相对时间是精确的。另外,组件是否更新并不取决于生产环境。

Demo #1

为了好玩,我在 todomvc APP 增加了一些严重的性能问题。你可以在 https://perf-demo.firebaseapp.com/?react_perf 试试。

要查看 timeline,打开 Chrome 开发工具,转到“Performance”选项,然后单击“Record”。再在App里添加一些 TODOs ,停止记录并查看timeline。你可以看看到底是哪些组件引起了性能问题 :)


工具 2: why-did-you-update


影响 React 中性能的最常见问题之一是不必要的渲染循环。默认情况下,React 组件将在父类渲染时重新渲染,即使他们的 props 没有改变。

例如,如果我有一个这样的简单组件:

有一个这样的父类组件:

无论何时父组件被渲染时,DumbComponent将被重新渲染,尽管其props并没有改变。

通常,如果渲染执行完成,并且虚拟DOM并没有改动,那么它是一个无用的渲染循环,因为渲染方法应该是纯的,而且没有任何副作用的。在一个大规模的React应用程序中,检测发生这种情况的发生的位置可能很棘手,但幸运的是,我们有一个可以帮助检测的工具!

使用 why-did-you-update

why-did-you-update 是一个挂钩到 React 检测潜在的不必要的组件渲染的库。即使props 没有改变,当一个组件的渲染方法被调用时它也会进行检测。

安装程序:

  • npm 安装:npm i --save-dev why-did-you-update

  • 在应用程序的任何地方添加此代码:


注:该工具用于本地开发很好,但要确保生产环境下被禁用,因为它会让你的应用变慢。


理解输出结果

what-did-you-update用于监测你的应用程序,记录其运行情况和可能出现的不必要地组件变动。它可以让你在渲染循环之前和之后看到其属性以确定该过程是否是不必要的。

Demo #2

为了说明why-did-you-update的原理, 我将该库安装在Code Sandbox中的TodoMVC应用程序上,这是一个在线React游戏机。打开浏览器控制台并添加一些TODOs,查看输出。

演示地址:https://codesandbox.io/s/xGJP4QExn

请注意,应用程序中有几个组件是没有必要渲染的。尝试使用上述技术来预防不必要的渲染。如果正确地完成,那么在控制台中应该没有任何why-did-you-update的输出。


工具 3: React Developer Tools


React Developer Tools Chrome Chrome扩展有一个内置的可视化组件更新功能。这有助于检测不必要的 render 周期。要使用它,首先要在这里安装扩展。

然后,打开扩展通过点击“React”选项卡中DevTools并检查“高亮更新(Highlight Updates)”。

然后,简单地使用你的应用程序。使组件交互,看 DevTools发挥它的魔力。

理解输出内容

 React Developer Tools 高亮显示在给定时间内重复渲染的组件。使用蓝色、绿色、黄色和红色表示更新的频率。

看到黄色或红色的不一定是坏事。当调整 slider 或 UI 元素频繁触发更新时就会出现这种情况。但是如果你点击一个简单的按钮,看到红色 —— 那可能就是什么东西出了问题。该工具的目的是发现更新不必要的组件。作为应用程序开发人员,您应该有一个大致的概念,在给定的时间内哪些组件应该更新。

demo #3

为了演示组件高亮,我在 TodoMVC 应用里更新了一些不必要的组件。

演示地址:https://highlight-demo.firebaseapp.com/

打开上面的链接,然后打开 React Developer Tools 并启用更新高亮。当您键入的文本输入头部时就会看到所有TODOs不必要的高亮。当你输入加快的时候,你会看到颜色的变化得更频繁。


修复不必要的渲染问题

一旦定位到了应用中的不必要重绘的组件,可以用上这些简单的修复方法。

使用 purecomponent

在上面的例子中, dumbcomponent 是其 props 的纯函数。也就是说,组件只需要在 props改变时重新渲染。React 有一个特殊类型的内置组件叫 PureComponent ,说的就是这种使用案例。

从React.PureComponent继承而不是从React.Component.


然后,组件只在props发生变化时才重新渲染。就是这么回事!

注意, purecomponent 只对 props 做简单对比,所以如果你使用的是复杂的数据结构,可能会导致错过一些 prop 的变化而使你的组件得不到更新。

实现 shouldComponentUpdate

shouldComponentUpdate 是一个组件方法,当 props 或 state 改变时,执行render之前就会被调用。如果 shouldcomponentupdate 返回true,render 将被调用,如果它返回false,则什么也不会发生。

这种方法可以通过判断它的 props 有没有改变让 React 避免重新渲染给定的组件。

例如,在上述例子中的 dumb component 实现shouldComponentUpdate



调试中的性能问题

如果您在自己的机器上运行应用程序,则React开发工具仅仅只是工作。如果你想在了解用户感兴趣的性能问题,试一下 LogRocket。

LogRocket  就像DVR 之于 Web应用程序,书面记录一切发生在你的网站上的情况。建议不要猜测问题发生的原因,而是通过重现 bug 或性能问题以快速了解问题的根本原因。

LogRocket 仪器记录 app 的性能数据,Redux 行为/状态、日志、错误、网络请求/响应信息头+信息主体,和浏览器元数据。它还记录页面上的HTML和CSS,重新生成甚至是最复杂的单页应用程序的超高清视频。

LogRocket | Logging and Session Replay for JavaScript Apps(https://logrocket.com/)


更多干货请前往公众号菜单栏“戳我”->“干货分享”查看。




推荐阅读

赶超 Java 和 PHP,Python 跃升为编程语言第一名

Vim 爱好者看过来,12 个实用的 Vim 使用技巧

Spring 思维导图,让 Spring 不再难懂(mvc篇)

2017 开发者生态报告:Java 最火,Go 最有前途

点击“阅读原文”查看更多精彩内容

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存