前端知识 2

Scroll Down

一、React中setState后发生了什么

在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。

经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。

在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。

在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

二、setState 为什么默认是异步

假如所有setState是同步的,意味着每执行一次setState时(有可能一个同步代码中,多次setState),都重新vnode diff + dom修改,这对性能来说是极为不好的。如果是异步,则可以把一个同步代码中的多个setState合并成一次组件更新。

三、setState 什么时候是同步

在setTimeout或者原生事件中,setState是同步的。

四、webpack 为什么慢

webpack是所谓的模块捆绑器,内部有循环引用来分析模块间之间的依赖,把文件解析成AST,通过一系类不同loader的加工,最后全部打包到一个js文件里。

webpack4以前在打包速度上没有做过多的优化手段,编译慢的大部分时间是花费在不同loader编译过程,webpack4以后,吸收借鉴了很多优秀工具的思路,

如支持0配置,多线程等功能,速度也大幅提升,但依然有一些优化手段。如合理的代码拆分,公共代码的提取,css资源的抽离

五、优化 Webpack 的构建速度

使用高版本的 Webpack (使用webpack4)
多线程/多实例构建:HappyPack(不维护了)、thread-loader
缩小打包作用域:
exclude/include (确定 loader 规则范围)
resolve.modules 指明第三方模块的绝对路径 (减少不必要的查找)
resolve.extensions 尽可能减少后缀尝试的可能性
noParse 对完全不需要解析的库进行忽略 (不去解析但仍会打包到 bundle 中,注意被忽略掉的文件里不应该包含 import、require、define 等模块化语句)
IgnorePlugin (完全排除模块)
合理使用alias
充分利用缓存提升二次构建速度:
babel-loader 开启缓存
terser-webpack-plugin 开启缓存
使用 cache-loader 或者 hard-source-webpack-plugin
注意:thread-loader 和 cache-loader 兩個要一起使用的話,請先放 cache-loader 接著是 thread-loader 最後才是 heavy-loader
DLL
使用 DllPlugin 进行分包,使用 DllReferencePlugin(索引链接) 对 manifest.json 引用,让一些基本不会改动的代码先打包成静态资源,避免反复编译浪费时间。

六、使用Webpack4带来的优化

V8带来的优化(for of替代forEach、Map和Set替代Object、includes替代indexOf)
默认使用更快的md4 hash算法
webpack AST可以直接从loader传递给AST,减少解析时间
使用字符串方法替代正则表达式
来看下具体使用

1.noParse

不去解析某个库内部的依赖关系
比如jquery 这个库是独立的, 则不去解析这个库内部依赖的其他的东西
在独立库的时候可以使用

  module: {
    noParse: /jquery/,
    rules:[]
  }
}

2.IgnorePlugin

忽略掉某些内容 不去解析依赖库内部引用的某些内容
从moment中引用 ./local 则忽略掉
如果要用local的话 则必须在项目中必须手动引入 import 'moment/locale/zh-cn'

  plugins: [
    new Webpack.IgnorePlugin(/\.\/local/, /moment/),
  ]
}

3.dillPlugin

不会多次打包, 优化打包时间
先把依赖的不变的库打包
生成 manifest.json文件
然后在webpack.config中引入
webpack.DllPlugin、Webpack.DllReferencePlugin

4.happypack -> thread-loader

大项目的时候开启多线程打包
影响前端发布速度的有两个方面,一个是 构建 ,一个就是 压缩 ,把这两个东西优化起来,可以减少很多发布的时间。

5.thread-loader

thread-loader 会将您的 loader 放置在一个 worker 池里面运行,以达到多线程构建。

把这个 loader 放置在其他 loader 之前,放置在这个 loader 之后的 loader 就会在一个单独的 worker 池(worker pool)中运行。

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve("src"),
        use: [
          "thread-loader",
          // 你的高开销的loader放置在此 (e.g babel-loader)
        ]
      }
    ]
  }
}

每个 worker 都是一个单独的有 600ms 限制的 node.js 进程。同时跨进程的数据交换也会被限制。请在高开销的loader中使用,否则效果不佳

6.压缩加速——开启多线程压缩

不推荐使用 webpack-paralle-uglify-plugin,项目基本处于没人维护的阶段,issue 没人处理,pr没人合并。

Webpack 4.0以前:uglifyjs-webpack-plugin,parallel参数

  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        parallel: true,
      }),
    ],
  },};

推荐使用 terser-webpack-plugin

  optimization: {
    minimizer: [new TerserPlugin(
      parallel: true   // 多线程
    )],
  },
};