Javascript is everywhere and to my mind is constantly gaining importance. Most programmers would agree that while Javascript itself is ugly, its "territory" sure is impressive. With the capabilities of HTML5 and the speed of modern browsers deploying an application via Javascript is an interesting option: It's probably as cross-platform as you can get.
The natural result are cross compilers. The predominant is probably GWT but there are several other options out there. My favourite is Coffeescript since it adds only a thin layer over Javascript and is much more "lightweight" than for example GWT.
There's just one thing that has been bugging me: Although my project is rather small performance has always been an important topic. Here's a quote
The GWT SDK provides a set of core Java APIs and Widgets. These allow you to write AJAX applications in Java and then compile the source to highly optimized JavaScript
Is Coffeescript optimized, too? Since Coffeescript seems to make heavy use of non-common Javascript functionality I'm worried how their performance compares.
Have you experience with Coffeescript related speed issues ? Do you know a good benchmark comparison ?
CoffeeScript is something that makes even good JavaScript code better. CoffeeScript compiled code can do everything that natively written JavaScript code can, only the code produced by using CoffeeScript is way shorter, and much easier to read.
In summary, CoffeeScript began as a fantastic idea (making it easier to write JavaScript code); ultimately, however, it didn't stand the test of time and was pushed out by JavaScript. Currently, hardly anyone remembers it.
C++ is more faster as compared to JavaScript. JavaScript is little slower as compared to C++ programming language.
Apologies for resurrecting an old topic but it was concerning me too. I decided to perform a little test and one of the simplest performance tests I know is to write consecutive values to an array, memory is consumed in a familiar manner as the array grows and 'for' loops are common enough in real life to be considered relevant.
After a couple of red herrings I find coffeescript's simplest method is:
newway = -> [0..1000000]
# simpler and quicker than the example from http://coffeescript.org/#loops
# countdown = (num for num in [10..1])
This uses a closure and returns the array as the result. My equivalent is this:
function oldway()
{
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
}
As you can see the result is the same and it grows an array in a similar way too. Next I profiled in chrome 100 times each and averaged.
newway() | 78.5ms
oldway() | 49.9ms
Coffeescript is 78% slower. I refute that "the CoffeeScript you write ends up running as fast as (and often faster than) the JS you would have written" (Jeremy Ashkenas)
Addendum: I was also suspicious of the popular belief that "there is always a one to one equivalent in JS". I tried to recreate my own code with this:
badway = ->
a = []
for i in [1..1000000]
a[i] = i
return a
Despite the similarity it still proved 7% slower because it adds extra checks for direction (increment or decrement) which means it is not a straight translation.
This is all quite intersting and there is one truth, coffee script cannot work faster than fully optimized javascript.
That said, since coffee script is generating javascript. There are ways to make it worth it. Sadly, it doesn't seem to be the case yet.
Lets take the example:
new_way = -> [0..1000000]
new_way()
It compiles to this with coffee script 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);
And the code provided by clockworkgeek is
function oldway()
{
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
}
oldway()
But since the coffee script hides the function inside a scope, we should do that for javascript too. We don't want to polute window right?
(function() {
function oldway()
{
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
}
oldway()
}).call(this);
So here we have code that does the same thing actually. And then we'd like to actually test both versions a couple of time.
Coffee script
for i in [0..100]
new_way = -> [0..1000000]
new_way()
Generated JS, and you may ask yourself what is going on there??? It's creating i
and _i
for whatever reason. It's clear to me from these two, only one is needed.
// 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);
So now we're going to update our 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);
So the results:
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
The js takes
time node test2.js
real 0m5.904s
user 0m0.000s
sys 0m0.000s
So you might ask yourself... what the hell coffee script is faster??? and then you look at the code and ask yourself... so let's try to fix that!
(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);
We'll then do a small fix to the JS script and change a[i] = i
to a.push(i)
And then lets try again...and then BOOM
time node test2.js
real 0m5.330s
user 0m0.000s
sys 0m0.000s
This small change made it faster than our CoffeeScript Now lets look at the generated CoffeeScript... and remove those double variables...
to this:
// 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);
and BOOM
time node test.js
real 0m5.373s
user 0m0.000s
sys 0m0.000s
Well what I'm trying to say is that there are great benefits to use a higher language. The generated CoffeeScript wasn't optimized. But wasn't that far from the pure js code. The code optimization that clockworkgeek
tried to use with using index directly instead of push actually seemed to backfire and worked slowlier than the generated coffeescript.
The truth it that such kind of optimization could be hard to find and fix. On the other side, from version to version, coffeescript could generate optimized js code for current browser or interpreters. The CoffeeScript would remain unchanged but could be generated again to speedup things.
If you write directly in javascript, there is now way to really optimize the code as much as one would with a real compiler.
The other interesting part is that one day, CoffeeScript or other generators to javascript could be used to analyse code (like jslint) and remove parts of the code where some variables aren't needed... Compile functions differently with different arguments to speed up things when some variables aren't needed. If you have purejs, you'll have to expect that there is a JIT compiler that will do the job right and its good for coffeescript too.
For example, I could optimize the coffee script one last time..by removing the new_way = (function...
from inside the for loop. One smart programmer would know that the only thing that happen here is reaffection the function on each loop which doesn't change the variable. The function is created in the function scope and isn't recreated on each loop. That said it shouldn't change much...
time node test.js
real 0m5.363s
user 0m0.015s
sys 0m0.000s
So this is pretty much it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With