工程化(8): JS 体积优化之代码压缩混淆的原理是什么?

Avatar
admin

通过 AST 分析,根据一些策略,来生成一颗更小体积的 AST 并生成代码。现代前端工程中,一般使用 terser 进行压缩混淆 JS。

常见用以压缩 AST 的几种方案如下:

去除多余字符: 空格,换行及注释代码语言:javascript复制// 对两个数求和

function sum (a, b) {

return a + b;

}

此时文件大小是 62 Byte, 「一般来说中文会占用更大的空间。」

多余的空白字符会占用大量的体积,如空格,换行符,另外注释也会占用文件体积。当我们把所有的空白符合注释都去掉之后,代码体积会得到减少。

「去掉多余字符之后,文件大小已经变为 30 Byte。」 压缩后代码如下:

代码语言:javascript复制function sum(a,b){return a+b}

替换掉多余字符后会有什么问题产生呢?

「有,比如多行代码压缩到一行时要注意行尾分号。」

压缩变量名:变量名,函数名及属性名代码语言:javascript复制function sum (first, second) {

return first + second;

}

如以上 first 与 second 在函数的作用域中,在作用域外不会引用它,此时可以让它们的变量名称更短。但是如果这是一个 module 中,sum 这个函数也不会被导出呢?那可以把这个函数名也缩短。

代码语言:javascript复制// 压缩: 缩短变量名

function sum (x, y) {

return x + y;

}

// 再压缩: 去除空余字符

function s(x,y){return x+y}

在这个示例中,当完成代码压缩 (compress) 时,代码的混淆 (mangle) 也捎带完成。「但此时缩短变量的命名也需要 AST 支持,不至于在作用域中造成命名冲突。」

解析程序逻辑:合并声明以及布尔值简化通过分析代码逻辑,可对代码改写为更精简的形式。

合并声明的示例如下:

代码语言:javascript复制// 压缩前

const a = 3;

const b = 4;

// 压缩后

const a = 3, b = 4;

布尔值简化的示例如下:

代码语言:javascript复制// 压缩前

!b && !c && !d && !e

// 压缩后

!(b||c||d||e)

解析程序逻辑: 编译预计算在编译期进行计算,减少运行时的计算量,如下示例:

代码语言:javascript复制// 压缩前

const ONE_YEAR = 365 * 24 * 60 * 60

// 压缩后

const ONE_YAAR = 31536000

以及一个更复杂的例子,简直是杀手锏级别的优化。

代码语言:javascript复制// 压缩前

function hello () {

console.log('hello, world')

}

hello()

// 压缩后

console.log('hello, world')

你关于这道题你的想法是什么,欢迎留言!