【问题标题】:How does Closure Compiler use type information to compile to faster JavaScript?Closure Compiler 如何使用类型信息编译成更快的 JavaScript?
【发布时间】:2014-02-06 23:16:27
【问题描述】:

Google 的 Closure Compiler 编译为更高效的 JavaScript。我可以想象一些简单的例子,例如 Closure Compiler 通过直接调用函数或用字面量替换常量来减少调用堆栈。但documentation 走得更远,说,

"闭包编译器可以使用关于 JavaScript 的数据类型信息 变量以提供增强的优化和警告。”

我的理解是类型化语言有两个好处:1) 类型检查可以在编译期间捕获错误——我可以看到 Closure Compiler 如何模拟这种行为——以及 2) 程序实际上执行得更快,因为它被编译到另一个语言(比如 Java 到 Java 字节码)。使用 Closure Compiler,输出仍然是 JavaScript。如何根据类型信息进行优化?

【问题讨论】:

  • 在确认是否(不需要)需要之后,它可能会删除多余的显式类型检查。不过我不知道。
  • 一个例子是内联代码。假设您有一些助手isUndefined,它可能内联typeof x === "undefined"。它还可以删除死代码并可以简化不良代码
  • @megawac 内联本身就是一个强大的优化,也是所有优化之母,但它需要的不仅仅是类型信息:它需要静态解析函数引用。这并不是说闭包编译器不能或不会这样做,而是 type 信息不允许内联。
  • 一个例子:它可以删除对数组元素的不需要的类型更改,这会导致围绕可以存储例如浮点数组的汇编代码低级数组重新装箱而不是混合数组。阅读更多关于 V8 优化的信息。

标签: javascript google-closure-compiler


【解决方案1】:

一个例子是 disambiguateProperties 功能,描述于http://closuretools.blogspot.com/2011/01/property-by-any-other-name-part-3.html

正如帖子所述,这允许编译器选择较短的属性名称。它还允许编译器消除更多的死代码。假设您在代码中调用x.foo(),并且有两种不同的类型都有foo 方法:

X1.prototype.foo = function() {
  // Lots and lots of code...
};


X2.prototype.foo = function() {
  // Lots and lots of code...
};

如果编译器不知道x 是什么类型,它必须在代码中保留两个长的foo 方法,即使其中一个可能永远不会被调用。如果它知道x 的类型是X1,那么它会将方法重命名为X1$fooX2$foo(或类似名称)。然后,它可以看到 X2$foo 从未被调用,因此它将它从编译代码中删除。这意味着要下载和解析的代码更少,因此它可以使页面感觉加载速度更快,并且 JS 解释器必须保留在内存中的函数更少。

【讨论】:

    【解决方案2】:

    闭包编译器中基于类型的“优化”本身并不是纯粹的优化。在编译器方面,它严格揭示了其他优化的机会。

    这是我在http://closure-compiler.appspot.com/home上构建的示例

    // ==ClosureCompiler==
    // @compilation_level ADVANCED_OPTIMIZATIONS
    // @use_types_for_optimization true
    // @formatting pretty_print
    // @output_file_name default.js
    // ==/ClosureCompiler==
    
    /** @constructor */
    function X(){}
    X.prototype.foo = function() {alert("X")};
    
    /** @constructor */
    function Y(){}
    Y.prototype.foo = function() {alert("Y")};
    
    window.i = new X();
    window.j = new Y();
    
    
    /**
     * @param {!X} x
     */
    window.keep = function(x) {
     x.foo();
    }
    

    如果您将 *use_types_for_optimization* true 切换为 false,您会注意到警报不再内联。请注意,如果没有类型信息,就不可能告诉 keep 的调用者始终是 X

    从这个意义上说,类型信息有助于内联。

    希望对您有所帮助。

    【讨论】:

      【解决方案3】:

      文档没有说明任何有关创建执行速度更快的代码的内容。编译器的重点一直是检查和代码大小。虽然它可以生成运行速度更快的代码(通常通过删除间接性),但它也可以通过创建违反 JS VM 的某些优化标准的代码(创建太大的函数等)来创建运行速度较慢的代码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-14
        • 1970-01-01
        • 2013-08-13
        • 2016-08-15
        相关资源
        最近更新 更多