zoukankan      html  css  js  c++  java
  • 使用Google Closure Compiler高级压缩Javascript代码注意的几个地方

    介绍

    GCC(Google Closure Compiler)是由谷歌发布的Js代码压缩编译工具。它可以做到分析Js的代码,移除不需要的代码(dead code),并且去重写它,最后再进行压缩。

    三种压缩模式

    GCC提供三种压缩模式:

    1)Whitespace only
    2)Simple
    3)Advanced
    

    我们以这段简单的代码为例

    function sayHello(name) {
      alert('Hello, ' + name);
    }
    sayHello('binnng');
    

    分别使用这三种压缩模式进行压缩:

    Whitespace only

    function sayHello(name){alert("Hello, "+name)}sayHello("binnng");
    

    发现只是简单的去除空格换行注释。

    Simple

    function sayHello(a){alert("Hello, "+a)}sayHello("binnng");
    

    Whitespace only要高端一点,在其基础上,还对局部变量的变量名进行缩短。这也是其他压缩工具所使用的压缩方式,如Uglify等,也是最为主流的压缩方式。比较安全。

    Advanced

    alert("Hello, binnng");
    

    会发现,Advanced级别的压缩改变(破坏)了原有代码结构,直接输出了代码最终运行结果,可见的确是分析重写破坏,但是对代码压缩做到了极致,极大的减少了代码量。

    注意的地方

    正因为GCC是这样的破坏性压缩工具,所以使用起来得异常小心,稍微不规范可能就会引起压缩报错或者压缩成功后却不能正常运行。那么,如果要使用Advanced级别压缩,要注意哪些呢?

    以下所有未指名级别的GCC压缩均为Advanced级别。

    GCC会对变量的属性名也进行压缩

    var data = {
      user: "binnng",
      age: "18"
    };
    
    if ("user" in data) {
      alert(data.age);
    }
    

    经过Uglify压缩:

    var data={user:"binnng",age:"18"};"user"in data&&alert(data.age);
    

    经过GCC压缩:

    var a={b:"binnng",a:"18"};"user"in a&&alert(a.a);
    

    会发现GCC压缩时,将变量的属性名也缩短,代码量减少了,但是却带来了问题,会发现以上GCC压缩后的代码运行其实是不正确的。因为属性名缩短改变后,data已经不再拥有名为user的属性了。

    那如何解决呢?

    var data = {
      user: "binnng",
      age: "18"
    };
    
    if (data.user) {
      alert(data.age);
    }
    

    这时候再经过GCC压缩:

    alert("18");
    

    直接输出了正确的结果。

    如果不想让GCC压缩属性名,比如在Ajax请求发送给后端接口的时候,可以将属性名用双引号包裹:

    var data = {
      "user": "binnng",
      "age": "18"
    };
    
    var ajax = function(url, data, callback) {
      (new window.XMLHttpRequest()).send(data);
      // ...
    }; 
    
    ajax("//baidu.com", data, function(res) {console.log(res)});
    

    这样经过GCC压缩后:

    (new window.XMLHttpRequest).send({user:"binnng",age:"18"});
    

    原封不动的保留了后端需要的参数名。

    全局变量要显式挂载在window下

    var foo = "1234";
    alert(widnow.foo);
    

    这时候,经过GCC压缩后:

    alert(window.a);
    

    有点莫名其妙。。因为在GCC中,不再认可隐式全局变量,所以上面的代码中在GCC眼里,foo是没有挂载到window下的,所以下文的window.foo其实是未定义的。

    要解决这个问题,必须将foo显式挂载到window下:

    window.foo = "1234";
    alert(widnow.foo);
    

    这样经过压缩后:

    window.a="1234";alert(widnow.a);
    

    这时候可能就会疑问,为何不直接压缩成alert("1234")呢?这是因为GCC不会去除挂载在window下的变量

    必要时导出变量函数等

    window.btnClick = function() {
      alert("clicked");
    };
    

    以上的代码经过压缩后成为:

    window.a=function(){alert("clicked")};
    

    此时,如果HTML中存在如下代码,就会报错。

    <a onclick="btnClick()">点我</a>
    

    这时候就需要导出函数

    window["btnClick"] = function() {
      alert("clicked");
    };
    

    用双引号包裹后,btnClick就保留了下来。在构造函数中,尤其需要注意导出,例如:

    var Animal = function(name) {
      this.name = name;
    };
    Animal.prototype.eat = function() {
      alert(this.name + " is eating!");
    };
    

    以上的代码经过GCC压缩后,什么都没剩下,因为GCC认为,代码中的代码都没有执行,属于dead code。既然这么写了,那肯定是需要它,提供给别人外部调用什么的,这时候就需要这么导出:

    var Animal = function(name) {
      this.name = name;
    };
    Animal.prototype.eat = function() {
      alert(this.name + " is eating!");
    };
    
    window["Animal"] = Animal;
    Animal.prototype["eat"]= Animal.prototype.eat;
    

    经过压缩后:

    function a(b){this.name=b}a.prototype.a=function(){alert(this.name+" is eating!")};window.Animal=a;a.prototype.eat=a.prototype.a;
    

    这时候,Animal这个方法成功的保留了下来。

    还有,在使用JSONP方式获取服务端数据的时候,也一定要导出callback方法名:

    var jsonpCb = function() {
      //...
    };
    
    getScript("/api/data?callback=jsonpCb");
    
    // 导出,否则jsonpCb会被压缩掉不能被识别
    window["jsonpCb"] = jsonpCb;
    

    所有业务代码合并压缩

    a.js

    var getName = function() {return "binnng"};
    

    b.js

    alert(getName());
    

    如果单独压缩a.jsb.js就会出问题,结果会是a.js中什么都没有,b.jsgetName方法未定义(undefined)。正确的做法则是,两者合并再进行压缩。

    结语

    GCC的高级压缩(Advanced)非常强大,对代码压缩做到了极致,但是其对代码书写要求也比较严格,并且破坏性压缩也被很多开发者所诟病。

    但是稍加注意,严格规范自身代码风格,了解GCC压缩方式原理,利用好GCC高级压缩,一定会大大减少JS的体积,从而大幅度的提升前端代码性能。

    另外,GCC像其他压缩工具一样,也有GruntGulp构建组件,可以很方便的去使用它。

    //原文地址:http://segmentfault.com/blog/laopopo/1190000002575760

  • 相关阅读:
    Intent
    What should we do next in general after collecting relevant data
    NOTE FOR Secure Friend Discovery in Mobile Social Networks
    missing pcap.h
    after building Android Source code
    plot point(one column)
    When talking to someone else, don't infer that is has been talked with others at first. It may bring repulsion to the person who is talking with you.
    进程基本知识
    Python input和raw_input的区别
    强制 code review:reviewboard+svn 的方案
  • 原文地址:https://www.cnblogs.com/afrog/p/4312368.html
Copyright © 2011-2022 走看看