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.
删除try/catch 不太好吧…