View Full Version : JavaScript Speed

05-08-2006, 01:22 PM
I wonder why programs made by javascript process slower than other programs made by other language, especially when encountering multiple and massive looping. Can anyone explain this and give a solution?

05-08-2006, 01:33 PM
Javascript is an interpreted language, not a compiled one.

05-08-2006, 01:47 PM
You may also:

- loop decremental (comparision with 0 is faster than comparision with another number)
- switch and while loops are faster than for/in loops
- innerHTML (if you don't need a correct DOM tree) is faster than DOM methods

05-08-2006, 05:54 PM

- loop decremental (comparision with 0 is faster than comparision with another number)

Great pages those. The offline editing tip was immediately applied in a page I'm building with good results.

About the loop decremental, from the text in the linked page (http://www.informit.com/articles/article.asp?p=31567&seqNum=6), it is not clear if the reason for its better performance is that the decrement operator is faster than the increment operator or if a comparison with 0 versus comparison with another number is the cause.

Reversing loop conditions so that they count down instead of up can double the speed of loops. Counting down to zero with the decrement operator (i--) is faster than counting up to a number of iterations with the increment operator (i++).

Bill Posters
05-08-2006, 05:57 PM
One more for the pile...
UserJS.org: Efficient Javascript Code (http://userjs.org/help/tutorials/efficient-code)

05-08-2006, 06:05 PM
when using increment i<arraylength, CPU do this, compare i with 0, compare arraylength with 0, and check which is the bigger

when using decrement i>=0, one of those 2 comparision term missed, as the second term is exactly 0.

05-08-2006, 06:19 PM
Ok. Now it is clear.

05-08-2006, 07:09 PM
Kor, this is simply not true.

In both RISC and CISC chips, there are op codes specifically for comparing two values. If you have x < y your opcodes will be:

load x, $register1
load y, $register2
branch-if-lessThan $register1, $register2, branch-address

if you have x < 0 your opcodes will be:
load x, $register1
load 0, $register2
branch-if-lessThan $register1, $register2, branch-address

The number of op-codes doesn't change. However, there is room for tweaking. First of all, loading a constant is faster than loading a variable, so x < y is a few miliseconds (literally something not normally measurable, like 3ms) slower than x < 5 or x < 9.

Based on that, it would seem that x < 0 is no different than x < 5 or x <9. However, almost all chips have a ZERO a register, so your opcodes for x < 0 would be

load x, $register1
branch-if-lessThan $register1, $ZERO, branch-address

So we cut out 1 single opcode for this comparison because zero is already loaded.

In order to see this effect at all in a JavaScript program, which is running interpreted in an engine in another program, you would have to be doing literally tens-of-thousands of comparisons. It's simply not worth it to re-arrange the logic in your code to get this benefit.

And for clarification, there are equivalent opcodes for all inequalities, so < is not faster or slower than <=. They are base instructions on the chip and therefore equivalent in cost.

++/-- is a different story.
(what I say here goes for both -- and ++)
The ++ operator can be prefixed or postfixed to a variable: x++ or ++x. If you do x++ the line is evaluated before x is incremented so:

var x = 5;
alert(x++); // *** alerts 5
alert(x); // *** alerts 6;
alert(++x); // *** alerts 7

In order for this to happen, a copy of x must be made in order to do the evaluation and then x is incremented. Creating this copy costs. However, this cost is not incurred when you prefix with ++. The variable is incremented and then the statement evaluated, no copying of values, no hidden costs.

Therefore, always using the prefix incrementer in your looping structures will provide a small improvement in speed. Much more so than comparison against zero, as comparison against zero is a single opcode whereas copying a value in a several.

But, looping backwards is STILL a slightly better idea because you save on one other thing: assignments. Assignment statements are costly. So:

var maxLength = array.length;
for (var i =0; i < maxLength; ++i)

is one more assignment than:

for (var i = array.length; i >= 0; --i)

for single loops, this is nothing. for nested loops, this can be important. example:

var maxCount;
var j;
for (var i = 0; i < 10000; ++i)
maxCount = some.value;
for (j = 0; j < maxCount; ++j)
array[j] = 5;

If you cut out the maxCount assignment by looping backwards, you save 10000 assignments, which is significant, considering you're also doing 10000 assignments of j = 0, and no, assigning 0 is not faster than assigning any other number.

Hope this clarifies things a bit.

05-08-2006, 09:36 PM
have I said something else?:)

05-08-2006, 10:43 PM
About the loop decremental, from the text in the linked page (http://www.informit.com/articles/article.asp?p=31567&seqNum=6), it is not clear if the reason for its better performance is that the decrement operator is faster than the increment operator or if a comparison with 0 versus comparison with another number is the cause.

Counting down and counting up are equally fast because adding or subtracting are equivalent. Where the difference comes is in the comparison for terminating the loop. Comparing to a constant hard coded value (whether zero or some other number) is more efficient and faster than comparing to some value that needs to be calculated. If you have a loop that is processing an array and you want to process each entry in the array then you need to know how many entries there are in the array. If you test the length of the array each time around the loop then that test is what will slow down the processing.

var j = ary.length;
for (var i = 0; i < j; i++) {...)

is almost as fast as

for (var i = ary.length; i >= 0; i--) {...}

since there is only one extra assignment in the first than in the second. Both are much faster than

for (var i=0; i < ary.length; i++) {...}

because with this last version the length of the array needs to be tested each time around the loop. This last version should only be used where the length of the array can be exprected to change during the processing of the loop.

Of course alternative coding that uses built in methods instead of loops will be faster still since those methods are using code compiled into the browser.

05-08-2006, 10:56 PM
The real solution to performance in JavaScript is the same as it is in other languages: Do less.

And knowing whether a certain way of doing things means a lot of action behind the scenes or not is one place to look for optimisations. The other places to look for optimisation is in reducing the use of expensive library calls and profiling the scripts to find out where most time is spent in your code. One solution to several performance problems is to try reducing the algorithmical complexity. However, this only increases the performance if the amount of time added by reiterating a problem is bigger than the constant cost of doing it that way.

05-09-2006, 01:11 AM
I tested to know the difference between:

for (var i = myArray.length -1; i >= 0 ; --i) {};

for (var i in myArray) {};

To my surprise the first form took 0.022 seconds and the second 0.637 (29X) in FF 1.08:

<script type="text/javascript">
function testeArray() {
var myArray = new Array();
for (i = 99999; i >= 0; --i) myArray[i] = i;

var start = new Date().getTime();
for (var i = myArray.length -1; i >= 0 ; --i) {};
var end = new Date().getTime();
alert((end - start) / 1000);

start = new Date().getTime();
for (var i in myArray) {};
end = new Date().getTime();
alert((end - start) / 1000);
<body onload="testeArray();">

What is happening here? I would expect the for in form to be reasonable optimized. I like to use it very much but now I will always consider before using it.

05-09-2006, 01:33 AM
Kor: I think the reason for that difference here is that the for..in loop construct compiles to an enumerator. This means that when checking the condition each time in the loop, it needs to access the next property (including check whether there actually exists a next property), and read out it's name.

The for loop on the other hand needs only to compare a variable to zero and decrement it.

It's a simple question of one loop doing less.