Skip to content

tree-shaking

什么是 tree-shaking

通过工具“摇”js 文件,将其中用不到的代码“摇”掉,属于性能优化。在 webpack 中有一个入口文件,相当于一颗树的主干,入口文件有很多依赖模块,在实际开发中,虽然依赖了某个模块,但是只使用了其中的某些功能。通过 tree-shaking 将没有使用的模块摇掉,来删除无用代码

支持 tree-shaking 的有

  • Rollup
  • Webpack2 开始
  • Closure compiler

tree-shaking 起初是 rollup 实现的,后来 webpack2 也增加了这个功能。其实更早,goole closure compiler 也做过类似的事情。

原理

tree-shaking 本质是消除无用的 js 代码,其实消除无用代码广泛存在于传统的编程语言编辑器中。编辑器可以判断出某些代码无用,然后消除这些代码,称为 DCE

tree-shaking 是 DCE 的一种新的实现,js 同传统的编程语言不同的是 js 大多数情况下需要通过网络进行下载然后执行。加载的文件越小,整体的执行时间更短。所以去除无用代码减少文件体积对 js 来说意义巨大

但是 tree-shaking 和传统的 DCE 的方法又不太一样,传统的 DCE 消灭不可能执行的代码,而 tree-shaking 关注的是消除没有用到的代码。

区别

  1. DCE
    • 代码不会执行,不可到达
    • 代码执行的结果不会被用到
    • 代码只会影响死变量(只写不读)

例子:

js
let foo = () => {
  let x = 1
  if (false) {
    console.log('never reached')
  }
  let a = 3
  return a
}

let baz = () => {
  var x = 1
  console.log(x)
  function unused() {
    return 5
  }
  return x
  let c = x + 3
  return c
}
baz()

传统编译型语言,都是由编译器将 Dead Code 从 ast 中删除,那 js 中由谁做 DCE 呢?

其实是由代码压缩优化工具 uglify,uglify 完成了 js 的 DCE

  1. tree-shaking

这个关注的是无用模块的消除,消除引用了但是并没有使用的模块。为什么 tree-shaking 是最近几年流行起来?而前端模块化概念已经有很多年历史了,其中 tree-shaking 的消除原理是依赖于 ES6 的模块特性

esm 的特点:

  • 只能作为模块顶层的语句出现
  • import 的模块名只能是字符串常量
  • Import binding 是 immutable 的

esm 的依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析。这是 tree-shaking 基础

  • 静态分析就是不执行代码,从字面量上对代码进行分析。es6 之前的模块化,比如可以动态 require 一个模块,只有执行后才知道引用的是什么模块,这个就不能通过静态分析去做优化

消除实验:

  • 在函数消除实验中,rollup 和 webpack 都通过,把没有用到的函数消除了

  • 在类消除实验中,rollup、webpack 全军覆没,都没有达到预期

    • rollup 只处理函数和顶层的 impport/export 变量。不能把没有用到的类消除掉
    • js 动态语言的特性使得静态分析比较困难
    • side Effect(副作用)广泛存在

tree-shaking 对函数效果较好

  1. 这些工具的 tree-shaking 对于无用代码,无用模块的消除都是有限的,有条件的。

如有转载或 CV 的请标注本站原文地址