焉逢

如何使你的 React 应用提速 15 倍

焉逢 · 2017-05-12翻译 · 520阅读 原文链接

即使不采用任何优化手段,React 在通常情况下也是足够快的。不过,你还是可以通过一些手段来提升它的性能。在 HelloSign 团队工作期间,我发现了一些快速的优化手段使得我们的应用有令人惊叹的表现。通过这些简单的优化,我可以将渲染时间从 3000 毫秒减少到不到 200 毫秒。

背景介绍

HelloSign 是一个基于云的电子签名工具,成立于2010年。你可以想象,这个工具有着非常庞大的 JavaScript 代码库。出色的签名体验离不开大量的客户端操作。最近,我们将大部分的代码迁移到了 React 。实际上,我们将很多地方都拆分成多个用 React 编写的 SPA。

即使在我加入这个团队之前,React 的表现已经让人很满意了,但我很快发现了一些可以提高应用运行速度的简单的优化手段。你应该看看以下步骤,这将给你的应用带来类似的提升。

制定一个性能标准

开始之前,你应该制定一个衡量性能的标准。否则无法检验修改带来的效果,那优化也就无从谈起了。

庆幸的是,Chrome 优秀的开发者工具可以帮到我们。其中有一个很少用到的功能就是 Timeline 时间线。它可以让你记录并分析你应用中的所有运行细节。你可以记录页面上的交互,找出潜在的内存泄露,衡量一个任务的运行时间,识别潜在的其他问题等。最重要的是,可以将记录下来的结果和你制定的性能标准进行比较。

这里有一个很棒的视频,详细介绍了 Timeline 的功能。点击查看

我们选择了登录页面的初始渲染到整个页面的最终渲染之间的时间,来作为衡量的标准。其中,静态资源的初始加载仍有待优化,简单起见,我们暂不考虑这个因素。比起点击页面的不同区域来尝试测试性能这种方式,测试渲染时间更显得简单直观,因为它可以反复进行。接下来,我们需要做的就是来到登录页面,打开开发者工具的 Timeline ,然后刷新页面。

需要注意的是,测试的时候要确保 Paint 和 Screenshots 这两个选项有勾选,这样你才能看到用户所看到的页面渲染过程。

最终,从记录的结果我们可以看到页面的渲染时间已经超过 3 秒了。这太长了……不过别灰心,我们还可以做一些事情来让它变快一点。

Performance Benchmark 1

将 NODE_ENV 变量设置为 'production'

这一步很容易被忽略,即使你是老司机。React 的文档中有提到这一点,不过它并没有涉及太多细节。React 有不错的开发者提示以及错误检查,不过这些只是为了开发时的需要。如果你有看过 React 源码的话,你会发现很多if (process.env.NODE_ENV != 'production') 这样的判断。这是用来运行用户并不需要的一些额外代码,而且调用 process.env.NODE_ENV 极其的慢。对于生产环境来说,我们可以移除掉所有这些不必要的代码。不过记住,不要在开发环境这样做,这会导致那些有用的提示被移除掉。

如果你在使用 Webpack 的话,你可以通过 DefinePlugin 这个插件来将所有 process.env.NODE_ENV 替换为 'production' ,然后通过 UglifyJsPlugin 就可以移除掉所有无用的代码。你可以参考下面这个例子:

// webpack.config.js
  ...
  plugins: [
    new webpack.DefinePlugin({
      // 这里有个常见的错误:忘了将字符串 'production' 序列化
      'process.env.NODE_ENV': JSON.stringify('production')
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
  ...

转换为 Constant Elements 和 Inline Elements

React 0.14 引入了对于 Babel 转换 Constant Elements 和 Inline Element 的优化支持。React Constant Elements 将 JSX elements 作为常量来对待并将它们提升至更高的作用域。换句话说,它提升了静态 elements ,从而减少了 React.createClass 的调用。React Inline Elements 将 JSX elements 转换为它们最终返回的对象字面量,同样减少了 React.createClass 的调用。

这一步很简单,我们在 package.json 文件中添加相关的 Babel 配置即可:

// package.json
  ...
  "babel": {
    "env": {
      "production": {
        "plugins": [
          "transform-react-constant-elements",
          "transform-react-inline-elements"
        ]
      }
    }
  },
  ...

最终测试 / 结论

最后,你需要再跑一遍测试,并将其和优化之前保存下来的测试结果进行比较。如你所见,总体运行时间约 200 毫秒,15 倍的提升!

相关文章