JavaScript's Statement Performance Questions

K

kun

Hi, Can you guys help me figure out the performance of each of these
statements.

Which is faster?
1. Making a new Array using
- var new_list = new Array(); or
- var new_list = []

2. Appending element using
- push('a')
or if i know the index, new_list;

3. ternary operator or
if() else ()

4. Trying to make isodd function
which is faster (! (is_even)) or (x%2!=0)

5. foreach or normal iteration

Thanks for your help.
 
L

Lasse Reichstein Nielsen

kun said:
Hi, Can you guys help me figure out the performance of each of these
statements.

First of all: Performance should only be a deciding factor if it is
a problem. I.e., make some performance measurements before changing
anything.

Second: You ask about the performance of a language construction in
a language with no guaranteed performance requirements. I.e., it's
entirely up to the implementation.

That said, there are some general characteristics of Javascript that
suggests which is likely to be faster, if any.
Which is faster?
1. Making a new Array using
- var new_list = new Array(); or
- var new_list = []

The latter is likely to be slightly faster. The former must do a
variable lookup on the global object to find the Array constructor,
which is likely to give it a slight overhead.

The way I would test it is to run a simple test like:

var x,i;
var t0 = new Date();
for(i = 0; i < 1000000; i++) {
x = new Array();
}
var t1 = new Date();
for(i = 0; i < 1000000; i++) {
x = [];
}
var t2 = new Date();
alert([t1-t0,t2-t1]);

In my Firefox, the results are approx. 877,570.
2. Appending element using
- push('a')
or if i know the index, new_list;


The push function must be looked up as a property of the object (it
might not be the build-in version) and it is variadic (can take an
arbitrary number of arguments), which means that the method call
must pass not only the single argument, but also the number of
arguments. Again, this suggests a slight overhead over the direct
property access, which is detectable as such at parse time.

I change the bodies of the loops in the test above to:
x.push(42);
and
y = 42;
(where x and y are initialized as empty arrays).

Firefox actually shows no discernible difference.
Safari 4 is actually a little faster doing push than assigning
to a numbered property, so is Chrome.

So much for my intuition.
3. ternary operator or
if() else ()

These are actually different in behavior.
If the branches contain a simple expression where the result can
be ignored, I expect them to behave identically.

And they do in Firefox.
4. Trying to make isodd function
which is faster (! (is_even)) or (x%2!=0)

Likely the latter, as the former performs a function call to
is_even (if I understand the question correctly) which does
the same computation as the latter does directly.
5. foreach or normal iteration

What is foreach?

/L
 
R

RobG

Hi, Can you guys help me figure out the performance of each of these
statements.

You could have tested it yourself quite easily. Below are some
results, all measures are approximate using IE 6 (except for forEach)
and Firefox 3.

Which is faster?
 1.  Making a new Array using
         - var new_list = new Array();  or
        -  var new_list = []

Browser dependent, testing in IE and Firefox shows new Array() is
about 25% slower. However, the difference is trivial since about
100,000 iterations are required to get a meaningful result. An array
literal is preferred as:

1. It's less code to type
2. It doesn't have the issues of understanding the arguments
that can be passed in a new Array(...) expression and
3. Some people just dislike using new.


 2. Appending element using
     - push('a')
   or if i know the index, new_list;


You don't need to know the index, the equivalent to push is:

new_list[new_list.length].

Again, browser dependent. In IE, push takes 3 times longer than
assigning to an index, Firefox is the opposite - push is 4 times
faster (takes 1/3 the time).

The big difference is that for 100,000 operations, IE was 250ms for
push, 78ms for assignment whereas Firefox was 20ms for push and 90ms
for assignment.

Since IE is such as slug that assignment is often used since that is
where the biggest speed difference will be noticed (if it is noticed
at all).

3. ternary operator or
   if() else ()

That likely depends on the browser and case. I usually only use it
for simple one line statements, anything else uses if..else. Note
that often if..else can be replaced with if(...) return and the else
part is just the rest of the logic.

4. Trying to make isodd function
      which is faster  (! (is_even)) or (x%2!=0)

What is "is_even"? If it's a function, then:

!is_even(n)

should be slower. The second can be just:

(x%2)

or if a boolean is required:

!!(x%2)


5. foreach or normal iteration

Browser dependent: forEach was implemented in JavaScript 1.6:

<URL: https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Objects:Array:forEach
but not all browsers have it. In Firefox, a while loop is 3 times
faster, which surprises me. Perhaps forEach should only be used with
sparse arrays.

Here's the test code, while and forEach lookup the value of the index
just to give them something to do:

function forEachVsWhile(){
var n = 100000;
var msg = [];
var s, i = n, t = [];

// Must assign values, forEach skips undefined and
// never set properties
while (i--) { t.push(i); }

s = new Date();
t.forEach(function(val, i, a){ a });
msg.push('forEach: ' + (new Date() - s));

// Reset i
i = n;
s = new Date();
while(i--) { t; }
msg.push('while: ' + (new Date() - s));

alert(msg.join('\n'));
}
 
R

RobG

 2. Appending element using
     - push('a')
   or if i know the index, new_list;


The push function must be looked up as a property of the object (it
might not be the build-in version) and it is variadic (can take an
arbitrary number of arguments), which means that the method call
must pass not only the single argument, but also the number of
arguments. Again, this suggests a slight overhead over the direct
property access, which is detectable as such at parse time.

I change the bodies of the loops in the test above to:
  x.push(42);
and
  y = 42;
(where x and y are initialized as empty arrays).

Firefox actually shows no discernible difference.


It does for me (Fx 3.0.8) - push is 3 to 4 times faster than
assignment (15-20ms vs 65-90ms), here's my code:

function testIt(){
var n = 100000;
var msg = [];
var i = n;
var s, t = [];

s = new Date();
while(i--) {
t.push(i);
}
msg.push('t.push: ' + (new Date() - s));

i = n;
t = [];
s = new Date();
while(i--) {
t = i;
}
msg.push('t: ' + (new Date() - s));

alert(msg.join('\n'));
}

testIt();


Perhaps there is something wrong in my methodology?
 
K

kunjaan

Thanks RobG and Lasse. Some of the statements were quite shocking. I
was extending the Array and Math Object in JavaScript and thought
performance would be a key deciding factor in my library. Are there
any other performance hacks that I could use?

Thanks a lot again.
 
E

Erwin Moller

kunjaan schreef:
Thanks RobG and Lasse. Some of the statements were quite shocking. I
was extending the Array and Math Object in JavaScript and thought
performance would be a key deciding factor in my library. Are there
any other performance hacks that I could use?

I think the message was: Don't use performance hacks unless you have a
performance problem. ;-)

Regards,
Erwin Moller


--
"There are two ways of constructing a software design: One way is to
make it so simple that there are obviously no deficiencies, and the
other way is to make it so complicated that there are no obvious
deficiencies. The first method is far more difficult."
-- C.A.R. Hoare
 
L

Lasse Reichstein Nielsen

RobG said:
On Apr 14, 3:08 pm, Lasse Reichstein Nielsen <[email protected]>
wrote:
I change the bodies of the loops in the test above to:
  x.push(42);
and
  y = 42;
(where x and y are initialized as empty arrays).

Firefox actually shows no discernible difference.


It does for me (Fx 3.0.8) - push is 3 to 4 times faster than
assignment (15-20ms vs 65-90ms), here's my code:

function testIt(){
var n = 100000;
var msg = [];
var i = n;
var s, t = [];

s = new Date();
while(i--) {
t.push(i);
}
msg.push('t.push: ' + (new Date() - s));

i = n;
t = [];
s = new Date();
while(i--) {
t = i;
}


Notice that you assign elements in the opposite order of push, i.e.,
the n-1'th element first. I have no idea why it makes a difference,
but perhaps it triggers some special handling of sparse arrays.
It is indeed much slower than using push.
msg.push('t: ' + (new Date() - s));

alert(msg.join('\n'));
}

testIt();


Perhaps there is something wrong in my methodology?


Perhaps not wrong, but it definitly shows a difference depending on
loop behavior and/or array access order.

If you change the loop from "while(i--)" to "for(i = 0;i < n;i++)",
I see t being approx. twice as fast as t.push.

/L
 
D

Dr J R Stockton

Tue said:
The way I would test it is to run a simple test like:
for(i = 0; i < 1000000; i++) {

Something like Q_ = K_ ; while (Q_--) { } should be slightly better.


Likely the latter, as the former performs a function call to
is_even (if I understand the question correctly) which does
the same computation as the latter does directly.

If 0 <= X < 2^32 something based on isodd = X & 1 should be
faster; and the pre-condition (after testing in FF 3.0.8) should
actually be Math.abs(X) <= Math.pow(2, 53) --- all bigger numbers should
appear to be even, naturally.

Removing the !=0 from X%2 makes no clear difference, suggesting that FF
optimised it out. X&1 is somewhat faster.

In IE7, removing !=0 also has no effect; X&1 is considerably faster.
 
R

RobG

RobG said:
I change the bodies of the loops in the test above to:
  x.push(42);
and
  y = 42;
(where x and y are initialized as empty arrays).
Firefox actually shows no discernible difference.

It does for me (Fx 3.0.8) - push is 3 to 4 times faster than
assignment (15-20ms vs 65-90ms), here's my code:
  function testIt(){
    var n = 100000;
    var msg = [];
    var i = n;
    var s, t = [];
    s = new Date();
    while(i--) {
      t.push(i);
    }
    msg.push('t.push: ' + (new Date() - s));
    i = n;
    t = [];
    s = new Date();
    while(i--) {
      t = i;
    }


Notice that you assign elements in the opposite order of push, i.e.,
the n-1'th element first. I have no idea why it makes a difference,
but perhaps it triggers some special handling of sparse arrays.
It is indeed much slower than using push.
    msg.push('t: ' + (new Date() - s));

    alert(msg.join('\n'));
  }

Perhaps there is something wrong in my methodology?

Perhaps not wrong, but it definitly shows a difference depending on
loop behavior and/or array access order.

If you change the loop from "while(i--)" to "for(i = 0;i < n;i++)",
I see t being approx. twice as fast as t.push.


Interesting - in Firefox, I consistently get decrement loops using --i
or i-- with for, while or do taking about 66ms. The same loops using
an increment are around 14ms, almost exactly the same speed as push,
which agrees with your original proposition - even though for an
incrementing do..while there is the extra work of a comparison in the
while expression:

n = 100000;
do {
t = i;
} while (++i < n)


Usually that extra comparison costs time, but not here.

In IE 6, the loops take the same time regardless of increment or
decrement (around 70ms) but push is about 3 times slower at around
250ms. Are IE 7 or 8 faster?

In any case, for less than say 1000 items, it wont make any noticable
difference to a user which method is used. :)
 
K

kunjaan

kunjaan schreef:


I think the message was: Don't use performance hacks unless you have a
performance problem. ;-)

Regards,
Erwin Moller

--
"There are two ways of constructing a software design: One way is to
make it so simple that there are obviously no deficiencies, and the
other way is to make it so complicated that there are no obvious
deficiencies. The first method is far more difficult."
-- C.A.R. Hoare

I was trying to make a Math library in JavaScript, so any performance
boosts will help. Thanks for all your help guys.
 
J

Jon Gómez

Lasse Reichstein Nielsen wrote:
[...]
Notice that you assign elements in the opposite order of push, i.e.,
the n-1'th element first. I have no idea why it makes a difference,
but perhaps it triggers some special handling of sparse arrays.
It is indeed much slower than using push. [...]
Perhaps not wrong, but it definitly shows a difference depending on
loop behavior and/or array access order.

If you change the loop from "while(i--)" to "for(i = 0;i < n;i++)",
I see t being approx. twice as fast as t.push.



That's pretty interesting!
Jon.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,102
Messages
2,570,646
Members
47,253
Latest member
AntwanNews

Latest Threads

Top