前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅谈 React Web App 优化

浅谈 React Web App 优化

作者头像
IMWeb前端团队
发布2019-12-03 16:20:00
8400
发布2019-12-03 16:20:00
举报
文章被收录于专栏:IMWeb前端团队IMWeb前端团队

本文作者:IMWeb HuQingyang 原文出处:IMWeb社区 未经同意,禁止转载

近些年随着网络和终端设备的性能提高,前端技术的发展与完善,各类纷繁复杂的单页 Web 应用(SPA)相继出现,Web 被赋予越来越重要的使命。配合 React 等 Web 框架,可以迅速地开发出功能强大的 SPA。不过,随着应用功能的迭代与体积的增加,Web 应用的性能对用户体验的影响也会日益凸显,因此,针对性的性能优化手段在 Web 开发中是必不可少的。

1. Chrome Performance Inspect 简介

工欲善其事必先利其器,在做性能优化时,需要选择一个强大的性能监控工具。在 React 16 之前,Facebook 官方支持使用 React-addons-perf 来进行 React 的性能检测,不过在 React 16 版本之后,React 停用了对 React-addons-perf 的支持。现在 Facebook 推荐使用使用强大的 Chrome Dev Tools 的 Performance Inspect 功能。 要使用 Performance Inspect 功能,只需要打开 Chrome Dev Tools,选择 Performance,点击记录按钮开始记录,等待记录完毕将会出现类似这样的界面:

从 1 到 4 每个区域分别为:

  1. 操作区域:如录制、刷新分析、清除结果等一系列操作
  2. 概览区域 :屏幕内容及性能影响因素(如:CPU、网络、FPS 等)随时间的变化
  3. 火焰图区域:记录具体性能消耗,相当于概览区域的完全版。虽然他们都是性能信息视图,但在该区域中,信息会变得更加详细、更加精准,甚至连每一次点击事件处理处理、每一次重绘视图等都有详细的记录,一般我们查看性能信息都在该区域进行。
  4. 总结区域:对选中的性能消耗记录进行总结,便于我们找到性能瓶颈所在。

在该工具中,每种颜色代表不同的意义:

  • 黄色:代表执行脚本的性能消耗
  • 绿色:代表渲染文档的性能消耗
  • 紫色:代表更新布局与样式的性能消耗
  • 灰色:代表其他性能消耗

更详细的参考这里不再赘述,可以参考这篇文档:如何使用 Timeline 工具 —— Google Developers

2. 提高初始化速度

下面我将结合最近在开发的 Tolstoy(托尔斯泰,Tolstoy.oa.com: 一个以 PB 为核心的自动化测试系统)来讲怎么一步一步地优化 Web 性能。 首先,我们需要我们需要找出我们的性能瓶颈所在:打开 Chrome Performance Inspect,点击记录并刷新页面,记录完成。

我们看到:虽然 bundle.js 主文件在 676ms 之后已经加载完毕,但 2s 之后才开始加载出主页面。

继续看发现解析和执行 bundle.js 花了 1.47s,也就是说在请求完 bundle.js 后的 1.47s 之内页面都处于完全空白状态,这导致在2s 之后 App 才初始化完毕,严重影响用户体验!

目前所有的业务逻辑代码、组件与依赖的框架等都打包在这一个文件里面,必然会导致执行这一个文件耗时较长,我们需要把依赖单独打包,保持 bundle.js 的轻量,不管是请求还是执行文件都会更快。同时,对组件使用懒加载,默认只加载必要的组件,以提高初始化速度。

配置 Webpack Dll Chunk:

  1. 首先新建 Webpack.dll.js:
代码语言:javascript
复制
const webpack = require('webpack');
const path = require('path');

const react = ["react", "react-dom", "react-router-dom", "mobx", "mobx-react"];
const antd = ["antd"];
const lib = ["react-json-view", "react-monaco-editor"];

module.exports = {
    context: path.join(__dirname, '../dll'),
    output: {
        path: path.join(__dirname, '../dll'),
        filename: '[name].dll.js',
        library: '[name]_[hash]',
    },
    entry: {
        "react": react,
        "antd": antd,
        "lib": lib,
    },
    plugins: [
          new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
        new webpack.DllPlugin({
            path:  path.join(__dirname, '../dll', '[name]-manifest.json'),
            name: '[name]_[hash]'
        })
    ]
};
  1. 然后在 Terminal 里运行 webpack --config ./config/webpack.dll.js,打包出 dll chunks。
  2. 最后,在 webpack 配置文件里加上:
代码语言:javascript
复制
{
    plugins: [
        new webpack.DefinePlugin(env.stringified),
        ...['react', 'lib', 'antd'].map(name => new webpack.DllReferencePlugin(({
            context: __dirname,
            manifest: require(`../dll/${name}-manifest.json`),
        }))),
        new AddAssetHtmlPlugin(['react', 'lib', 'antd'].map(name => ({
            filepath: require.resolve(`../dll/${name}.dll.js`),
            hash: true,
            includeSourcemap: false
        })))
    ]
}

更多信息可以参考:WebpackDllPlugin

使用 LazyLoad

  1. 首先运行 npm install --save react-lazyload
  2. 实现两个 Helper Function 来封装 LazyLoad 组件:

```jsx harmony function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component'; }

function lazy(Component) { const HOC = props => ; HOC.displayName = LazyHOC(${getDisplayName(Component)}); return HOC; }

代码语言:javascript
复制
1. 在组件声明时使用 LazyLoad 封装:
   ![](https://raw.githubusercontent.com/HuQingyang/Think/master/react-optiomize/pic/C8F54BE2-1FE4-4837-A70F-C5B090EA8ED1.png)
   当然,如果你不喜欢装饰器语法,也可写成`export default lazy(Uploader);`

经过上面的步骤,再次进行性能测量:

![](https://raw.githubusercontent.com/HuQingyang/Think/master/react-optiomize/pic/3B78871B-8403-4C36-B0BD-84A59A80FAC8.png)

Bingo!我们的 App 的初始化耗时从 2s 优化到 700 ms,速度提升 65%!

## 3. 提升应用内响应

除了初始化速度之外,App 内的响应速度也是优化的一方面。得益于 React 优秀的设计与 VirtualDOM 高效的 Diff 与 Patch,开发者并不需要特别需要关注 App 的性能,唯一需要注意的是:尽量避免不必要的 rerender。
这里我们需要使用另一个工具:[why-did-you-update](https://github.com/maicki/why-did-you-update),它会在 Virtual-DOM 产生不必要的更新时轰炸你的控制台!

首先,运行 `npm install --save-dev why-did-you-update`。
然后,编辑你的入口文件:

```jsx
import { whyDidYouUpdate } from 'why-did-you-update';
if (process.env.NODE_ENV !== 'production') {
    whyDidYouUpdate(React);
}

最后,刷新页面:

可以看到 “Route” 组件有 10 次不必要的 rerender,“Route” 是在 “App” 组件内被引入的,我们看 “App” 组件:

```jsx harmony class App extends Component { render() { return (

{routes.map(route => )}

); } }

代码语言:javascript
复制
很明显,App 组件只是单纯的返回值,并没有内部状态,这时应该优先 **使用 PureComponent**。可以把 PureComponent 看做是默认实现了 shouldComponentUpdate 的组件,只要传入值不变,就一定不会重新渲染。这里 App 并没有 props(传入值),也就不会产生不必要的 render 了。

更改 “App” 组件为:

```jsx harmony
class App extends PureComponent { ... }

另外,在每次删除用例(去掉表格中的一行)时,也会产生 render:

我们看 render 该表格的组件:

```jsx harmony class UseCaseList extends Component { ... render() { const { store: { ucses } } = this.props; return (

({ ...i, key: index })))} columns={this.columns} /> ); } }

代码语言:javascript
复制
在这里渲染 List 时使用了 `key = index` ,这会在去掉 List 中的一个 Item 时,引起该 Item 之后的所有 Item 重新渲染。
因为 React 的虚拟 DOM 会使用依赖一个独一无二的 Key 去缓存一个节点,避免反复渲染。现在假设我们在一个 List 中有如图6个 Item 使用 Index 作为 Key 渲染:
![](https://raw.githubusercontent.com/HuQingyang/Think/master/react-optiomize/pic/70B7ACCC-1CAC-4515-BEB7-7FB90B91B47F.png)
当我们删掉 “C” item 时:
![](https://raw.githubusercontent.com/HuQingyang/Think/master/react-optiomize/pic/6E5E3D97-509B-41BE-BC57-6F866EEB1D1E.png)
“C” 之后的所有 Item 的 Key 都会发生改变,一旦 Key 发生改变,React 就会认为这是一个新的组件二把它重新渲染一遍,显然这会造成性能浪费。因此,应该**合理使用 Key** 来避免 rerender。

因此,我们渲染 Table 的数据可以改为:

```jsx harmony
ucses.map((i, index) => ({ ...i, key: i.id }))

还有很多其他的优化点如:使用 shouldComponentUpdate使用 Immutable.js使用 Shallow Compare使用无状态组件(Pure Function) 等,由于篇幅及时间原因这里不再赘述。

该系列持续更新,欢迎关注 HuQingyang (胡青杨) · GitH

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-05-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Chrome Performance Inspect 简介
  • 2. 提高初始化速度
    • 配置 Webpack Dll Chunk:
      • 使用 LazyLoad
      相关产品与服务
      应用性能监控
      应用性能监控(Application Performance Management,APM)是一款应用性能管理平台,基于实时多语言应用探针全量采集技术,为您提供分布式性能分析和故障自检能力。APM 协助您在复杂的业务系统里快速定位性能问题,降低 MTTR(平均故障恢复时间),实时了解并追踪应用性能,提升用户体验。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档