Google Closure Compiler压缩优化规则初探
前不久,Google发布了一系列与WEB开发相关的工具,包括Closure Compiler、Closure Library与Closure Templates,其中Closure Compiler被Google称之为Javascript 优化器(Javascript Optimizer)。通过编译,Compiler可以使代码获得更佳的紧凑性和更高的性能。它不仅能删除无用的代码,同时还会重写和压缩代码以获得更好的下载和运行速度。此外,它还能检查代码中的语法、变量引用以及变量类型,并在发现问题后给出警告。
Compiler对代码的压缩优化包括三个级别:
- WHITESPACE_ONLY 仅仅删除代码中的空白符以及注释
- SIMPLE_OPTIMIZATIONS 在第一级的基础上重命名局部变量,经过这个级别的优化,代码的体积往往可以减少很多,并且并不会影响被压缩脚本与其他脚本的交互。
- ADVANCED_OPTIMIZATIONS 最高级别的压缩优化,除了1、2级的一些常规策略外还会采取一些非常规策略来实现压缩的最大化。不过需要注意的是,如果是代码库则需要慎用这个级别的压缩,因为它会替换所有的变量名,除非使用这里介绍的方式来处理
对于脚本压缩和优化,我最感兴趣的是它所遵循的一些规则,通过查看源码不难发现,这些规则都是作为独立的Class来实现的,具体位于源码目录下的 com\google\javascript\jscomp,其中程序入口位于CompilerRunner.java中,真正的解析是在Compiler.java中实现的。在Compiler.java中的optimize方法中,依次列出了各种优化规则,摘出部分罗列如下:
| 规则 | 示例 | 描述 |
|---|---|---|
| 删除注释、空白符 | - | - |
| 内联简单函数 |
压缩前
function Test(a,b){ return a + b};
var sum = Test(document.x,document.y);
alert(sum);
压缩后
alert(document.x+document.y);
|
会根据函数的复杂程度以及函数调用次数来决定是否内联处理 |
| 变量替换以及表达式计算 |
压缩前
var week = document.offsetHeight;
var a = 3600*24*week;
alert(a);
function MyFun(a,b){
if( a+b > 5 )
return 'GT 5';
else
return 'LTE 5';
}
alert(MyFun(1,2));
压缩后
alert(86400*document.offsetHeight);
alert("LTE 5");
|
- |
| 删除未引用对象(函数、变量、语句等) |
压缩前
//未有效引用的变量
var unusedGlobalVar = 'Hello World!';
//未有效引用的函数
function UnUsedFun(){
alert(unusedGlobalVar);
}
function MyFun(timeout){
setTimeout(function(){
alert('timeout');
},timeout);
//多余的return
return;
}
var rlt = MyFun(1000);
document.title = rlt;
压缩后
function a(b){setTimeout(
function(){alert("timeout")},b)}
var c=a(1000);document.title=c;
|
- |
| if语句替换为三目运算 |
压缩前
function MyFun(a,b){
if( a+b > 5 )
return 'GT 5';
else
return 'LTE 5';
}
alert(MyFun(window.a,window.b));
if( window.test )
alert('hello');
压缩后
alert(window.a+window.b>5?
"GT 5":"LTE 5");window.test&&alert("hello");
|
- |
| 常量内联 |
压缩前
var A = "Hello world!";
var el = document.createElement('p');
p.innerHTML = A;
压缩后
document.createElement("p");
p.innerHTML="Hello world!";
|
- |
| 删除不会执行到的代码片段 |
压缩前
if( false )
alert('Me');
else
alert('He');
压缩后
alert("He");
|
- |
| 简化变量申明 |
压缩前 var var1 = 1; var var2 = 2; var var3 = 3; alert(var1 + var2 + var3); 压缩后 var var1=1,var2=2,var3=3;alert(var1+var2+var3); 如果赋值相同则会变成 var var1=var2=var3=1; |
- |
| 属性读取方式优化 |
压缩前 a['b]=1; 压缩后 a.b=1; |
如果引号中属性名包含’-'等特殊字符则不会处理 |
| 匿名函数处理 |
压缩前
var hello = function(name) {
alert('Hello, ' + name);
}
hello('New user');
压缩后
function hello(a){alert("Hello, "+a)}
hello("New user");
|
- |
| 删除try/catch |
压缩前
try {
function f() { return 1;}
var g = f;
} catch(e) {}
压缩后
var g=f;function f(){return 1};
|
- |
| prototype 简写 |
压缩前
function B() { ... }
B.prototype.foo = function() { ... }
B.prototype.bar = function() { ... }
压缩后
function B() { ... }
x = B.prototype
x.foo = function() { ... }
x.bar = function() { ... }
|
如果有多个给prototype添加属性的语句,则会将prototype进行简写处理 |
| 变量重用 |
压缩前
function print(x){alert(x);};
var x = 1; print(x);
var y = 2; print(y);
压缩后
function print(x){alert(x);};
var x = 1; print(x);
x = 2; print(x);
|
可以减少代码长度、更好的gzip压缩效果 |
| 无关联的属性名称替换成相同的变量名 |
压缩前 Foo.fooprop = 0; Foo.fooprop2 = 0; Bar.barprop = 0; 压缩后 Foo.a = 0; Foo.b = 0; Bar.a = 0; |
可以使更多的变量获得更短的名字,提高压缩效果 |
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
删除try/catch 不太好吧…