coffeescript 比 javascript 快吗?
Posted
技术标签:
【中文标题】coffeescript 比 javascript 快吗?【英文标题】:is coffeescript faster than javascript? 【发布时间】:2012-02-21 06:25:15 【问题描述】:javascript 无处不在,在我看来,它的重要性不断提高。大多数程序员都会同意,虽然 Javascript 本身很丑,但它的“领域”确实令人印象深刻。借助 html5 的功能和现代浏览器的速度,通过 Javascript 部署应用程序是一个有趣的选择:它可能是您可以获得的跨平台。
自然的结果是交叉编译器。主要的可能是 GWT,但还有其他几种选择。我最喜欢的是 Coffeescript,因为它只在 Javascript 上添加了一个薄层,并且比 GWT 更“轻量级”。
只有一件事一直困扰着我:虽然我的项目很小,但性能一直是一个重要的话题。这是一个报价
GWT SDK 提供了一组核心 Java API 和小部件。这些允许 您用 Java 编写 AJAX 应用程序,然后将源代码编译为 高度优化的 JavaScript
Coffeescript 也优化了吗?由于 Coffeescript 似乎大量使用了不常见的 Javascript 功能,我担心它们的性能比较如何。
您是否遇到过与 Coffeescript 相关的速度问题? 你知道一个好的基准比较吗?
【问题讨论】:
CoffeeScript 使用了哪些不常见的功能? "JavaScript 本身很丑" -> false. 我同意 Raynos:糟糕的代码就是糟糕的代码,可以用任何语言编写。 【参考方案1】:Coffescript 直接编译为 JavaScript,这意味着任何 Coffeescript 源代码在 JS 中总是存在一对一的等价物。没有什么不寻常的。性能提升可以来自优化的东西,例如Coffescript 将数组长度存储在 for 循环中的单独变量中,而不是在每次迭代中都请求它。但这也应该是 JavaScript 中的一种常见做法,只是语言本身没有强制执行。
【讨论】:
不错的答案。我想如果 JS CoffeeScript 生成的比开发人员所拥有的更智能,那么可能会有性能提升……我猜这并不少见 创建一种包含最佳实践的新语言是个好主意。我看到的问题是当它试图变得太花哨时。每个人都知道为什么 CoffeeScript 会生成它所生成的 JS 是有意义的。 @Raynos CoffeeScript 和 Javascript 之间的区别在于,如果你用 Coffeescript 编写,新版本的 CoffeeScript 实际上可以优化它生成 javascript 的方式。如果您直接用javascript编写。那你还是完蛋了。无需重写代码,您就可以使用更快的代码。 这也适用于 JavaScript。与许多其他 JavaScript 引擎相比,Google 的 V8 是一个巨大的性能改进,并且会继续变得更好。但是您不必重写 JavaScript 即可使用 Google Chrome。 @Daff 这并不完全正确,除非 JIT 引擎能够更好地优化以前无法优化的东西。 CoffeeScript 可以以不同的方式重新构建,以创建将被 JIT 引擎有效优化的代码。不同之处在于,coffeescript 只需重建即可。 JS 必须手动重写,以便 JIT 更容易对其进行优化。【参考方案2】:简短回答:否。
CoffeeScript 生成 javascript,因此它的最大可能速度等于 javascript 的速度。但是,虽然您可以在 低级 优化 js 代码(是的,这听起来很讽刺)并获得一些性能提升 - 但使用 CoffeeScript 是无法做到的。
但是在选择 CS 而不是 JS 时,代码速度不应该是您关心的问题,因为对于大多数任务来说差异可以忽略不计。
【讨论】:
【参考方案3】:很抱歉复活了一个老话题,但这也与我有关。我决定进行一个小测试,我所知道的最简单的性能测试之一是将连续值写入数组,随着数组的增长,内存以熟悉的方式消耗,并且“for”循环在现实生活中很常见,可以考虑相关的。
经过几个红鲱鱼我发现coffeescript最简单的方法是:
newway = -> [0..1000000]
# simpler and quicker than the example from http://coffeescript.org/#loops
# countdown = (num for num in [10..1])
这使用了一个闭包并返回数组作为结果。我的等价物是这样的:
function oldway()
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
如您所见,结果是相同的,并且它也以类似的方式增长了一个数组。接下来我在 chrome 中分析了 100 次并取平均值。
newway() | 78.5ms
oldway() | 49.9ms
Coffeescript 慢了 78%。我反驳说“你编写的 CoffeeScript 最终运行的速度与你编写的 JS 一样快(而且通常快于)”(Jeremy Ashkenas)
附录:我也对“JS 中总是存在一对一等价物”这一流行观点持怀疑态度。我试图用这个重新创建我自己的代码:
badway = ->
a = []
for i in [1..1000000]
a[i] = i
return a
尽管相似,但仍被证明慢了 7%,因为它增加了额外的方向检查(增量或减量),这意味着它不是直接翻译。
【讨论】:
为什么要为一个有趣的答案道歉。我没想到会有这么大的差异。当然有人可能会争辩说,将 0 到 1000000 的所有数字添加到数组中并不是一种正常的用例,而且您只是查看了一个浏览器。但是78%!?这很难 +1 这应该是答案,因为作者花时间测量并指出咖啡生成的js中的问题。使用咖啡的唯一原因就是提高生产力。 闭包通常被报告为 Javascript 中的性能消耗。 Coffeescript 广泛使用它们,即使它们不是绝对必要的。 +1 并且它在后台处理类和继承的方式与“未定义”和未定义非常可怕,第二个未定义被转换为 void 0 并与 null 进行比较。如果有人读过 JS 书,那这两本书都不好【参考方案4】:这一切都很有趣,而且有一个事实,coffee 脚本不能比完全优化的 javascript 运行得更快。
也就是说,因为咖啡脚本正在生成 javascript。有办法让它变得值得。可悲的是,它似乎还不是这样。
举个例子:
new_way = -> [0..1000000]
new_way()
它使用咖啡脚本 1.6.2 编译为此
// Generated by CoffeeScript 1.6.2
(function()
var new_way;
new_way = function()
var _i, _results;
return (function()
_results = [];
for (_i = 0; _i <= 1000000; _i++) _results.push(_i);
return _results;
).apply(this);
;
new_way();
).call(this);
而clockworkgeek提供的代码是
function oldway()
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
oldway()
但是由于咖啡脚本将函数隐藏在范围内,我们也应该为 javascript 这样做。我们不想污染窗口对吧?
(function()
function oldway()
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
oldway()
).call(this);
所以这里我们的代码实际上做同样的事情。然后我们想实际测试这两个版本几次。
咖啡脚本
for i in [0..100]
new_way = -> [0..1000000]
new_way()
生成的JS,你可能会问自己那里发生了什么???无论出于何种原因,它都会创建i
和_i
。从这两个中我很清楚,只需要一个。
// Generated by CoffeeScript 1.6.2
(function()
var i, new_way, _i;
for (i = _i = 0; _i <= 100; i = ++_i)
new_way = function()
var _j, _results;
return (function()
_results = [];
for (_j = 0; _j <= 1000000; _j++) _results.push(_j);
return _results;
).apply(this);
;
new_way();
).call(this);
所以现在我们要更新我们的 Javascript。
(function()
function oldway()
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
var _i;
for(_i=0; _i <= 100; ++_i)
oldway()
).call(this);
所以结果:
time coffee test.coffee
real 0m5.647s
user 0m0.016s
sys 0m0.076s
time node test.js
real 0m5.479s
user 0m0.000s
sys 0m0.000s
js 需要
time node test2.js
real 0m5.904s
user 0m0.000s
sys 0m0.000s
所以你可能会问自己......什么地狱咖啡脚本更快???然后您查看代码并问自己...所以让我们尝试修复它!
(function()
function oldway()
var a = [];
for (var i = 0; i <= 1000000; i++)
a.push(i);
return a;
var _i;
for(_i=0; _i <= 100; ++_i)
oldway()
).call(this);
然后我们将对 JS 脚本做一个小修复并将 a[i] = i
更改为 a.push(i)
然后让我们再试一次...然后 BOOM
time node test2.js
real 0m5.330s
user 0m0.000s
sys 0m0.000s
这个小改动让它比我们的 CoffeeScript 更快 现在让我们看看生成的 CoffeeScript...并删除那些双变量...
对此:
// Generated by CoffeeScript 1.6.2
(function()
var i, new_way;
for (i = 0; i <= 100; ++i)
new_way = function()
var _j, _results;
return (function()
_results = [];
for (_j = 0; _j <= 1000000; _j++) _results.push(_j);
return _results;
).apply(this);
;
new_way();
).call(this);
和繁荣
time node test.js
real 0m5.373s
user 0m0.000s
sys 0m0.000s
我想说的是,使用高级语言有很多好处。生成的 CoffeeScript 没有经过优化。但是离纯js代码不远了。 clockworkgeek
尝试直接使用 index 而不是 push 的代码优化实际上似乎适得其反,并且比生成的咖啡脚本运行得更慢。
这种优化很难找到和修复的事实。另一方面,从版本到版本,coffeescript 可以为当前浏览器或解释器生成优化的 js 代码。 CoffeeScript 将保持不变,但可以再次生成以加快速度。
如果您直接用 javascript 编写代码,现在可以像使用真正的编译器一样优化代码。
另一个有趣的部分是有一天,CoffeeScript 或其他 javascript 生成器可用于分析代码(如 jslint)并删除不需要某些变量的部分代码...使用不同的参数以不同的方式编译函数在不需要某些变量时加快速度。如果您有 purejs,则必须期望有一个 JIT 编译器可以正确完成工作,并且对咖啡脚本也有好处。
例如,我可以最后一次优化咖啡脚本......通过从 for 循环中删除 new_way = (function...
。一位聪明的程序员会知道,这里唯一发生的事情就是在每个循环上重新影响函数,这不会改变变量。该函数是在函数范围内创建的,并且不会在每个循环中重新创建。那就是说它不应该有太大变化......
time node test.js
real 0m5.363s
user 0m0.015s
sys 0m0.000s
差不多就是这样。
【讨论】:
你对生成最后一个块的 CoffeeScript 代码做了什么改变? 我删除了_i
。我没有更改咖啡脚本代码。我编辑了生成的代码。
好的。起初,我以为您提出了一个实用的解决方案,可以让 CoffeeScript 输出更好的代码。我现在看到你改变了这一点,只是为了表明 CoffeeScript 转译器是一个在技术上总是可以改进的层,以产生越来越多的优化代码。
是的,这就是重点,只是如果 JIT 足够聪明,它应该不会产生影响。这意味着那里和那里都有改进的地方。
确实如此。你的答案应该是被接受的,因为它提供了一个更强有力的结论以及到达那里的方式。干得好。【参考方案5】:
我想在 Loïc Faure-Lacroix 的回答中添加一些内容...
看来,您只打印了一个浏览器的时间。顺便说一句,根据 jsperf,“x.push(i)”并不比“x[i] = i”快:https://jsperf.com/array-direct-assignment-vs-push/130
Chrome: push => 79,491 ops/s; direct assignment => 3,815,588 ops/s;
IE Edge: push => 358,036 ops/s; direct assignment => 7,047,523 ops/s;
Firefox: push => 67,123 ops/s; direct assignment => 206,444 ops/s;
另一点 -> x.call(this) 和 x.apply(this)... 我看不出有任何性能原因。甚至 jsperf 也证实了这一点:http://jsperf.com/call-apply-segu/18
Chrome:
direct call => 47,579,486 ops/s; x.call => 45,239,029 ops/s; x.apply => 15,036,387 ops/s;
IE Edge:
direct call => 113,210,261 ops/s; x.call => 17,771,762 ops/s; x.apply => 6,550,769 ops/s;
Firefox:
direct call => 780,255,612 ops/s; x.call => 76,210,019 ops/s; x.apply => 2,559,295 ops/s;
首先要提一下 - 我使用的是实际的浏览器。
其次 - 我通过一个 for 循环扩展了测试,因为只需一次调用,测试就会缩短......
最后但并非最不重要 - 现在所有浏览器的测试如下:
这里我使用的是 CoffeeScript 1.10.0(用他的回答中给出的相同代码编译)
console.time('coffee');// added manually
(function()
var new_way;
new_way = function()
var i, results;
return (function()
results = [];
for (i = 0; i <= 1000000; i++) results.push(i);
return results;
).apply(this);
;
// manually added on both
var i;
for(i = 0; i != 10; i++)
new_way();
).call(this);
console.timeEnd('coffee');// added manually
现在是 Javascript
console.time('js');
(function()
function old_way()
var i = 0, results = [];
return (function()
for (i = 0; i <= 1000000; i++)
results[i] = i;
return results;
)();// replaced apply
var i;
for(i = 0; i != 10; i++)
old_way();
)();// replaced call
console.timeEnd('js');
for 循环的极限值很低,因为再高则测试速度会非常慢(10 * 1000000 次调用)...
结果
Chrome: coffee: 305.000ms; js: 258.000ms;
IE Edge: coffee: 5.944,281ms; js: 3.517,72ms;
Firefox: coffee: 174.23ms; js: 159.55ms;
在这里我必须提到,在这个测试中,咖啡并不总是最慢的。您可以通过在 firefox 中测试这些代码来看到这一点。
我的最终答案:
首先要说-我对coffeescript并不是很熟悉,但我研究了它,因为我正在使用Atom Editor并想尝试在那里构建我的第一个包,但又回到了Javascript...... 所以如果有什么不对的地方可以指正。
使用coffeescript,您可以编写更少的代码,但如果涉及到优化,代码就会变得繁重。我自己的观点 -> 我在这种 Coffeescripting 语言中看不到任何所谓的“生产力”......
回到性能:: 最常用的浏览器是 Chrome 浏览器 (src: w3schools.com/browsers/browsers_stats.asp) 有 60%,我的测试也表明手动输入的 Javascript 运行速度比Coffeescript(除了 IE ... - 更快)。对于较小的项目,我会推荐 Coffeescript,但如果没有人介意,请保留您喜欢的语言。
【讨论】:
以上是关于coffeescript 比 javascript 快吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 JavaScript forEach 循环/函数转换为 CoffeeScript
Rails - 从 JavaScript 调用 CoffeeScript