前端性能优化

构建优化

webpack优化

(1) build Cache

  • 开启缓存选项 exg:bable-loader?cacheDirectory

(2)减少代码体积

  • code splitting想把不变的代码单独抽离出来,方便浏览器缓存,提升加载速度
  • 使用optimization,减少总体积

    optimization: {
           splitChunks: {      
           //用于拆分代码,找到 chunk 中共同依赖的模块,取出来生成单独的 chunk([SplitChunksPlugin])
               chunks: 'all'
           },
           runtimeChunk: true, 
           // 将 webpack 生成的 runtime 作为独立 chunk ,runtime 包含在模块交互时,模块所需的加载和解析逻辑(manifest),所以你每次改动都会影响它,如果不把它提取出来的话,等于app.js每次都会改变,缓存就失效了
           minimize:true // 用于控制压缩的开关,开发环境默认关闭,生产环境默认开启[uglifyjs-webpack-plugin]
           optimization.minimizer:用于配置压缩项及其配置项
       }
  • css文件压缩,用到了mini-css-extract-plugin
  • 部分依赖转移到CDN上,避免每次编译过程都有webpack处理
  • 删除未使用的依赖

    • 通过 package.json 的 "sideEffects" 属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 "pure(纯的 ES2015 模块)",无副作用的,由此可以安全地删除文件中未使用的部分

(3)减少目录检索范围

  • 通过exclude/include,减少loader遍历范围,加快编译速度

(4)减少检索路径

  • resolve.alias 配置解析别名

(5)使用DllPlugin/DllReferencePlugin进行预先构建用某种方法实现了拆分 bundles,同时还大大提升了构建的速度。

  • 将改变频率较小的第三库和依赖单独打包构建(npm包)
    (i)新建一个单独webpack配置文件 (webpack.dll.config.js)
    (ii)在这个配置文件中,使用 webpack DllPlugin 生成 manifest.json 文件和 Dll 模块文件。也可以引入诸如 uglifyPlugin 对第三方依赖进行压缩等处理
    (iii) 在正常的 webpack 配置文件中,使用 webpack DllReferencePlugin 解析上一步生成的 manifest.json

    new webpack.DllReferencePlugin({
        context: path.join(__dirname),
        manifest: require('./manifest.json')})

(6)happypack

  • happypack 的原理是让loader可以多进程去处理文件 将需要通过loader处理的文件先交给happypack去处理,happypack 在收集到这些文件的处理权限后,统一分配CPU资源

    var HappyPack = require('happypack'),
    os = require('os'),
     happyThreadPool = HappyPack.ThreadPool({ size:os.cpus().length });
    
    modules: {
    loaders: [
      {
        test: /\.js|jsx$/,
        loader: 'HappyPack/loader?id=jsHappy',
        exclude: /node_modules/
      }
    ]
    }
    plugins: [
    new HappyPack({
     // 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
      id: 'jsHappy',
      cache: true,
      threadPool: happyThreadPool,
      
    // 如何处理 .js 文件,用法和 Loader 配置中一样
    
      loaders: [{
        path: 'babel',
        query: {
          cacheDirectory: '.webpack_cache',
          presets: [
            'es2015',
            'react'
          ]
        }
      }]
    }),
    //如果有单独提取css文件的话
    new HappyPack({
      id: 'lessHappy',
       // 如何处理 .js 文件,用法和 Loader 配置中一样
      loaders: ['style','css','less']
    })
    ]

(7)模块热替换(它允许在运行时更新所有类型的模块,而无需完全刷新) ---开发环境

  • 更新[webpack-dev-server]配置,使用 webpack 内置的 HMR 插件[HotModuleReplacementPlugin]

     
     ```
     devServer: {
       contentBase: './dist',
       hot: true
    }
    
    
     plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
         title: '模块热替换'
       }),
        new webpack.HotModuleReplacementPlugin()
      ]
    
    ```

(8)懒加载 不即时加载所有资源,而是在需要的时候才加载

  • @babel/plugin-syntax-dynamic-import

    test: /\.js$/,
    exclude: /node_modules/,
    use:[
       {
           loader: 'babel-loader', 
           options: {//如果有这个设置则不用再添加.babelrc文件进行配置
               "babelrc": false,// 不采用.babelrc的配置
               "plugins": [
                   "@babel/plugin-syntax-dynamic-import"
               ]
           }
       }
    ]

代码优化

JS优化

  • 变量名在不影响语义的情况下尽量简单(可以选择首字母命名)
  • 尽量使用局部变量(避免作用域链一层一层查找)
  • 避免增长作用域链(with/try...catch..)

    • with使对象的属性可以像全局变量使用,增长了作用域链
    • try...catch中catch在作用域顶端增加对象,命名的异常对象,影响较少
  • 条件判断

    • 条件分支较多时将出现概率较大的放在最上面
    • 层数较深时,switch比if性能更高
    • 对应的结果是单一值,可以使用数组
      var a = [v0,v1,v1]; return a[value];
  • 快速循环

    • 尽量少使用for in 循环,需要查询hash键
    • 循环总次数使用局部变量
      var len = arr.length;for(var i = 0; i< len ; i++){}
  • 高效存取数据

    • 字面量值和变量中存取数据是最快的,从数组元素和对象属性中存取值相对较慢
    • 减少对象的查找 将其缓存在变量中
  • 使用第三库时,用子模块代替整个包

    import _ from 'loadsh';(不推荐)
    import forEach from 'lodash/forEach';(推荐)
  • 字符串连接

    • 追加字符串,最好使用s+=anotherStr
    • 连接多个字符串,不要个个使用+=,使用s+=a+b+c
  • 类型转换

    • 数字转换字符转 性能:("" +) > String() > .toString() > new String()
    • 浮点数转换成整型使用Math.floor()/Math.round(),parseInt()将字符串转换成数字,使用内部对象,没有使用太多查询方法和调用的时间,速度最快
  • 尽量使用json格式创建对象或者数组,而不是new,json格式引擎直接解释,new需要调用构造器
  • 对字符串进行循环操作(替换,查找),使用正则(c写的api,速度高于js循环)
  • 对象查询[]会比.查询快
  • 减少对dom的操作

    • 对dom操作,保证N次创建(js),最后一次写入(html)

react优化

  • 不要滥用{...this.props},只传递组件需要的props,传递太多或层次太深,会加重shouldComponentUpdate的负担
  • 使用箭头函数来绑定函数
  • 尽量使用稳定常量作为key值,避免index
  • 尽量少用不可控的refs、DOM操作
  • props,state的数据尽量简单,明了,扁平化,便于数据对比,遍历等
  • 使用React Fragments避免额外的标记
  • 尽量少使用内联函数,每次调用render函数都会创建一个新的函数实例,渲染阶段会额外增加垃圾回收和绑定新函数的操作
  • 避免在componentWillMount()中异步请求 初始化不会获取数据,重新渲染才会获取数据
  • 组件化

    • 组件分类(展示型、交互型、数据型、高阶组件)
    • 可复用性 组件自己控制自己内部的state,setState只用局部更新视图,降低组件之间的耦合度
    • 组件拆分细(可读性强,维护性高,便于复用)
    • 耦合度低
  • 减少render次数

    • Immutable 配合 shouldComponentUpdate 具体请看这里
    • 使用防抖函数来减少不必要的setState,从而减少render次数

css优化

  • 尽量少使用style属性修改元素,每次修改元素style,会触发回流
  • 频繁触发重绘和回流,会导致UI频繁渲染,最终导致js变慢

    • 回流必将触发重绘,重绘不一定触发回流
    • 用translate(重绘)代替top(回流)
    • 用opacity代替visibility(重绘)
    • 不要使用table布局,很小的改动会导致整个table重新布局
  • 尽量减少标签选择器的使用
  • 减少ID标签使用,多使用样式选择器(具有通用性)

html优化

  • 避免使用空的src和href,浏览器会将当前页面的url作为其属性值

备注:
webpack4生产环境优化
webpack4大结局:加入腾讯IM配置策略,实现前端工程化环境极致优化
webpack4 的30个步骤打造优化到极致的 react 开发环境,如约而至
前端性能优化指南


喝冬瓜汤的丁小白
45 声望4 粉丝