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来实现的,具体位于源码目录下的 comgooglejavascriptjscomp,其中程序入口位于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.

1 Comment »

 
 

Leave a Reply

您必须 登录 才能发表评论。