Javascript无处不在,在我看来,它一直在变得越来越重要。大多数程序员都同意,虽然Javascript本身很难看,但它的“领域”确实令人印象深刻。凭借HTML5的功能和现代浏览器的速度,通过Javascript部署应用程序是一个有趣的选择:它可能是你可以获得的跨平台。
自然结果是交叉编译器。主要可能是GWT,但还有其他几种选择。我最喜欢的是Coffeescript,因为它只在Javascript上添加了一个薄层,并且比例如GWT更“轻量级”。
只有一件事让我烦恼:虽然我的项目相当小,但性能始终是一个重要的话题。这是一个引用
GWT SDK提供了一组核心Java API和小部件。这些允许 你用Java编写AJAX应用程序然后编译源代码 高度优化的JavaScript
Coffeescript也被优化了吗?由于Coffeescript似乎大量使用非常见的Javascript功能,我担心他们的性能如何比较。
您是否有过与Coffeescript相关的速度问题的经验? 你知道一个很好的基准比较吗?
答案 0 :(得分:37)
为复活一个古老话题而道歉,但这也让我很担心。我决定执行一个小测试,我知道的一个最简单的性能测试是将连续值写入数组,随着数组的增长,内存以熟悉的方式消耗,并且'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%,因为它增加了对方向(增量或减量)的额外检查,这意味着它不是直接翻译。
答案 1 :(得分:23)
这一切都非常有趣,而且有一个道理,咖啡脚本无法比完全优化的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 Now更快,让我们看看生成的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);
和BOOM
time node test.js
real 0m5.373s
user 0m0.000s
sys 0m0.000s
我想说的是,使用更高级的语言有很多好处。生成的CoffeeScript未进行优化。但与纯粹的js代码相差不远。 clockworkgeek
试图直接使用索引而不是推送使用的代码优化实际上似乎适得其反,并且比生成的coffeescript工作得慢。
事实上,这种优化很难找到并修复。另一方面,从版本到版本,coffeescript可以为当前的浏览器或解释器生成优化的js代码。 CoffeeScript将保持不变,但可以再次生成以加快速度。
如果你直接在javascript中编写,现在有办法真正优化代码,就像使用真正的编译器一样。
另一个有趣的部分是,有一天,CoffeeScript或javascript的其他生成器可用于分析代码(如jslint)并删除不需要某些变量的代码部分...使用不同的参数编译函数在不需要某些变量时加快速度。如果你有purejs,你将不得不期望有一个JIT编译器能够正确地完成工作并且它对coffeescript也有好处。
例如,我可以最后一次优化咖啡脚本..通过从for循环中删除new_way = (function...
。一个聪明的程序员会知道,这里唯一发生的事情是对每个循环的函数的影响不会改变变量。该函数在函数范围内创建,不会在每个循环中重新创建。那说不应该改变太多......
time node test.js
real 0m5.363s
user 0m0.015s
sys 0m0.000s
所以这就是它。
答案 2 :(得分:11)
简短回答:否。
CoffeeScript生成javascript,因此其最大可能速度等于javascript的速度。但是你可以在低级优化js代码(是的,这听起来很讽刺)并获得一些性能提升 - 使用CoffeeScript你不能这样做。
但是在选择CS over JS时,代码的速度不应该是您的关注,因为大多数任务的差异可以忽略不计。
答案 3 :(得分:8)
Coffescript直接编译到JavaScript,这意味着在JS中对于任何Coffeescript源始终存在一对一的等价物。关于它没有什么不相同之处。性能提升可以来自优化的事物,例如事实上Coffescript将Array长度存储在for循环中的单独变量中,而不是在每次迭代中请求它。但这也应该是JavaScript中的常见做法,它本身并不是由语言本身强制执行的。
答案 4 :(得分:1)
我想在LoïcFaure-Lacroix的答案中添加一些内容......
看来,您只打印了一个浏览器的时间。根据jsperf,btw“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;
另一点 - &gt; 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编辑器并想尝试在那里构建我的第一个包,但是又回到了Javascript ... 所以,如果有任何错误,你可以纠正我。
使用coffeescript,您可以编写更少的代码,但如果涉及优化,则代码会变得很重。我自己的意见 - &gt;我没有在这种Coffeescripting语言中看到任何所谓的“生产力”......
回到表演::最常用的浏览器是Chrome浏览器(src:w3schools.com/browsers/browsers_stats.asp),占60%,我的测试也显示手动输入的Javascript运行速度比Coffeescript(IE除外...... - 快得多)。我会推荐Coffeescript用于较小的项目,但如果没有人介意,请保持你喜欢的语言。