我正在撰写Google Chrome扩展程序。由于JavaScript文件是从磁盘加载的,因此它们的大小几乎不重要。
我一直在使用Google Closure Compiler,因为显然它可以进行性能优化以及减少代码大小。
但是我在Closure Compiler的输出顶部注意到了这一点:
var i = true, m = null, r = false;
这一点显然是为了减少文件大小(整个脚本中true
/ null
/ false
的所有后续使用都可以替换为单个字符)。
但是肯定会有轻微的性能影响吗?读取文字true
关键字比按名称查找变量并找到其值为true
...?
这种表现值得担心吗?谷歌闭包编译器还有什么可以实际上减慢执行速度吗?
答案 0 :(得分:42)
让我们看看关闭团队对此的看法。
编译器是否在我的应用程序的执行速度和下载代码大小之间进行权衡?
是。任何优化编译器都需要权衡。 某些大小优化确实会引入较小的速度开销。但是,Closure Compiler的开发人员一直小心不要引入大量额外的运行时。 某些编译器的优化甚至会降低运行时间(请参阅下一个问题)。
编译器是否针对速度进行优化?
在大多数情况下,较小的代码是更快的代码,因为下载时间通常是Web应用程序中最重要的速度因素。减少冗余的优化也可以加快代码的运行时间。
我断然挑战他们在这里做出的第一个假设。使用的vars名称的大小并不直接影响各种JavaScript引擎如何处理代码 - 事实上,如果你调用变量supercalifragilisticexpialidocious
或x
,JS引擎并不在意(但我作为程序员肯定)。如果您担心交付,下载时间是最重要的部分 - 我怀疑该工具根本无法解决的数百万件事情导致脚本运行缓慢。
要真实地理解为什么你的问题可能是,首先你需要问的是"是什么让JavaScript变得快或慢?"
当然,我们遇到了一个问题,"我们在谈论什么JavaScript引擎?"
我们有:
这里有没有人真的认为他们都一样?特别是JScript和V8?哎呀!
再说一次,谷歌关闭编译代码时,哪个引擎可以构建东西?你感觉幸运吗?
好的,因为我们永远不会涵盖所有这些基础,所以我们可以尝试在这里更普遍地看一下#34; old" vs" new"代码。
以下是one of the best presentations on JS Engines I've ever seen中此特定部分的快速摘要。
这里的主要区别在于新引擎引入了JIT编译器。
从本质上讲,JIT将优化您的代码执行,以便它可以更快地运行,但如果它不喜欢发生的事情,它会转向并使其再次变慢。
你可以通过这样的两个函数来做这些事情:
var FunctionForIntegersOnly = function(int1, int2){
return int1 + int2;
}
var FunctionForStringsOnly = function(str1, str2){
return str1 + str2;
}
alert(FunctionForIntegersOnly(1, 2) + FunctionForStringsOnly("a", "b"));
通过谷歌关闭运行实际上将整个代码简化为:
alert("3ab");
并且本书中的每个指标都更快。这里真正发生的是它简化了我的一个非常简单的例子,因为它做了一些部分执行。这是你需要小心的地方。
Lets say we have a y-combinator in our code,编译器把它变成这样的东西:
(function(a) {
return function(b) {
return a(a)(b)
}
})(function(a) {
return function(b) {
if(b > 0) {
return console.log(b), a(a)(b - 1)
}
}
})(5);
不是真的更快,只是缩小了代码。
JIT通常会看到实际上你的代码只需要为该函数提供两个字符串输入,并返回一个字符串(或第一个函数的整数),这将它放入特定于类型的JIT中,这使得它真的快。现在,如果谷歌闭包做了一些奇怪的事情,比如将具有几乎相同签名的那些函数转换成一个函数(对于非平凡的代码),如果编译器执行JIT不喜欢的事情,则可能会失去JIT速度。
通常,您的代码更快。您可以介绍各种JIT编译器不喜欢的东西,但如果您的代码使用较小的函数并且正确的原型面向对象设计,它们将会很少见。如果你考虑编译器正在做的全部范围(更短的下载和更快的执行),那么像var i = true, m = null, r = false;
这样的奇怪的事情可能是值得的 - 虽然他们的运行速度较慢,但是编译器会做出权衡,总寿命更快。
值得注意的是,网络应用程序执行中最常见的瓶颈是文档对象模型,如果您的代码很慢,我建议您在那里付出更多努力。
答案 1 :(得分:10)
在现代浏览器中,使用文字true
或null
与变量相比,几乎在所有情况下都会使绝对没有区别(因为在零中;它们正是相同)。在极少数情况下,变量实际上更快。
因此,保存中的那些额外字节值得,而且不需要任何费用。
true
vs变量(http://jsperf.com/true-vs-variable):
null
vs变量(http://jsperf.com/null-vs-variable):
答案 2 :(得分:2)
我认为会有轻微的性能损失,但在较新的现代浏览器中不太重要。
请注意,Closure Compiler的标准别名变量都是全局变量。这意味着,在JavaScript引擎需要线性时间来导航功能范围(例如IE< 9)的旧浏览器中,嵌套函数调用越深,找到保持“true”的变量所需的时间越长或者“false”等几乎所有现代JavaScript引擎都优化了全局变量访问,因此在许多情况下这种惩罚不再适用。
此外,在编译代码中,除了赋值或参数之外,确实不应该有很多地方直接看到“true”或“false”或“null”。例如:if (someFlag == true) ...
大多只是编写if (someFlag) ...
,由编译器编译成a && ...
。你们大多只在作业(someFlag = true;
)和参数(someFunc(true);
)中看到它们,这种情况实际上并不常见。
结论是:尽管很多人怀疑Closure Compiler的标准别名(包括我)的用处,但你不应该期望任何重大的性能影响。不过,您也不应期望在gzip压缩尺寸方面有任何实质性好处。