Faster Loops With JavaScript
Sorry, that I have not posted about any Frameworks in the past two weeks; I am overwhelmed with my work. However, tonight I cannot sleep, so I thought I would write something. I was writing an event handler function and realized that I was coding loops in a way that is not usually possible in other languages. Let’s discuss this technique, which can help improve the run-time of certain iterative for loops.
Suppose you have an event callback function with multiple triggers and a collection of something that you need to iterate through each time the callback function is made (like rows in a table or list items in a list). You then need to do something different to the collection depending on what trigger hit the callback function. In most languages you would have a for loop containing a switch statement with N cases (or if statements if you absolutely cannot use a switch). Here is an example that executes a function on each list item depending on the trigger id:
function callback(e) {
var items = document.body.getElementsByTagName('li');
var trigger = Event.getTarget(e); // this is a Framework function that is really useful
var id = trigger.id;
for (var i=0, j=items.length; i<j; i++) {
switch (id) {
case 'id1':
someFunctionForId1(items[i]);
break;
case 'id2':
someFunctionForId2(items[i]);
break;
case 'id3':
someFunctionForId3(items[i]);
break;
case 'id4':
someFunctionForId4(items[i]);
break;
default: // any other id
someFunctionForId5(items[i]);
break;
}
}
}
This is perfectly valid code and will work great on small sets, because the switch statement has a very small run-time cost (switches are very quick seek structures in JavaScript), and on a small set, you will not execute the statement many times. The runtime as an equation would be:
k1 * n = r
where k1 = the constant cost of the switch
n = the number of values in the array
and r = run-time
There is a better way to write this function, where the select statement is only executed once:
function callback(e) {
var items = document.body.getElementsByTagName('li');
var trigger = Event.getTarget(e); // this is a Framework function that is really useful
var id = trigger.id;
var fx = null;
switch (id) {
case 'id1':
fx = someFunctionForId1;
break;
case 'id2':
fx = someFunctionForId2;
break;
case 'id3':
fx = someFunctionForId3;
break;
case 'id4':
fx = someFunctionForId4;
break;
default: // any other id
fx = someFunctionForId5;
break;
}
for (var i=0, j=items.length; i<j; i++) {
fx(item[i]);
}
}
For this callback the runtime is:
(k2 + k1) + (c * n) = r
where k1 = the constant cost of the switch
k2 = the constant cost of assigning the function to variable fx
c = the cost of seeking and executing the function fx
n = the number of values in the array
and r = run-time
I have not done the actually runtime analysis, so I do not have the exact numbers, but you should not have to stretch your imagination far to assume that the cost of c < k1, so as long as the number of iterations (n) are overwhelm the constant (k1 + k2), then the latter algorithm is faster. The exact equation for this comparison is:
(k1 + k2) + (c * n) = k1 * n
where k1 = the constant cost of the switch
where k2 = the constant cost of assigning the function to variable fx
c = the cost of seeking and executing the function fx
n = the number of values in the array
computing for n, you get:
n = (k1 + k2) / (k1 - c)
If you have time, try profiling some loop code to figure the exact numbers. My assumption is that n is between 10 & 20, so anytime I iterate on a list greater than 10 and can use this pattern, I do.

Hmm, you can avoid the switch completely by storing your function names in an object:
fxs = {’id1′:func1,’id2′:func2}
then all you need to do is fxs[id](); to execute.
Comment by Chris Heilmann — July 5, 2007 @ 4:11 am
Thanks, Chris. That is great point. ^_^
Comment by admin — July 5, 2007 @ 8:50 am