Found Code: JavaScript getElementById, Performance, and the $ Function.

From what I’ve seen, most of the popular JavaScript frameworks out there provide some form of the $ method. This method is usually a cross-browser translation of document.getElementById with a few extras. What this means is instead of always having to type document.getElementById("myId") you can now type $("myId"). All-in-all it’s a very nice shortcut and will probably cut quite a bit of typing out of your JavaScript projects. My problem is with the number of times I’ve come across inefficient uses of this helper function because it’s easier to type. This usually manifests itself as something along these lines (this example written using prototype.js):

1
2
3
4
5
6
if( $("myId").style.display.toLowerCase() == 'none' ) {
	$("myId").style.color = 'red';
	$("myId").style.height = '10px';
	$("myId").style.width = '100px';
	$("myId").style.display = 'block';
}

This code looks pretty concise, if you know what the $ function does it’s also pretty simple, but take a second to think about performance. In this code it’s possible that you’re calling document.getElementById five times! Ignoring whatever else the $ function does, the document.getElementById function could traverse the entire DOM on each call. (I’m not saying it does, but you really don’t know what the browser is doing under the covers and since you’re designing for all JavaScript enabled browsers, it’s better safe than sorry!) If you actually had to type out the document.getElementById you would probably consider something like this:

1
2
3
4
5
6
7
var myId = document.getElementById("myId");
if( myId.style.display.toLowerCase() == 'none' ) {
	myId.style.color = 'red';
	myId.style.height = '10px';
	myId.style.width = '100px';
	myId.style.display = 'block';
}

With this code, you’re only calling document.getElementById once, and therefore only traversing the DOM once. Makes a little more sense right? Let’s look at some metrics.

For this experiment, let’s make the assumption that the larger your document is the longer it will take to perform a DOM traversal, so in order to see some results we’ll need a decent sized document. For that we’ll go to wikipedia and grab something off the front page, in this case it’ll be Harry Potter. To get my test document I viewed the source, grabbed the main body content, and pasted it into a new HTML document. I also removed all of the images since I didn’t want broken images or to be hitting wikipedia’s servers for my experiment. I wrote a quick JavaScript class that will do my benchmarking, and a quick test case that calls my two methods above as well as two other methods and single calls to both the $ function and the document.getElementById function. To perform the benchmark, I run each method 1000 times. I initially tried smaller numbers but there was not enough visual difference to prove my theory since JavaScript is only accurate to the millisecond. You can find the test code here, the benchmark class here, and you can run the test here. I’m using Firebug Lite for the console logging, but if you have Firebug installed it will use the Firebug console. As I said before I just wrote the benchmarking class, but look for a future post and improved version now that the seed has been planted.

I have successfully run the test on Safari 3.1 on OSX 10.5, Firefox 2.0.0.13 and IE 7.0.6000.16643 on Windows Vista Business 64-bit, and IE 6.0.2900… and Safari 3.0.4 on Windows XP Pro. My results were as follows:

getElementById $ function Un-optimized $ function Optimized $ function Un-optimized getElementById Optimized getElementById
Safari Mac 1 ms 4 ms 67 ms 37 ms 42 ms 33 ms
Firefox 7 ms 9 ms 177 ms 121 ms 154 ms 118 ms
IE 7 273 ms 291 ms 1829 ms 364 ms 1688 ms 337 ms
IE 6 312 ms 297 ms 1960 ms 484 ms 1735 ms 375 ms
Safari Windows 0 ms 0 ms 94 ms 47 ms 47 ms 46 ms

Across the board the optimized functions performed better, and in most cases the $ function was slightly slower than the document.getElementById function. The most surprising result is Safari on Windows because it’s actually the slowest machine that these tests were run on. The only problem that I can think of with this test is that it does quite a bit of looking up by id, and that’s probably not an accurate test case, but even if you’re cutting out only a few milliseconds on an event, somebody will notice the improvement. I’m welcome to any suggestions or comments on my testing methodology.


2 Responses to “Found Code: JavaScript getElementById, Performance, and the $ Function.”

  1. Sam:

    Just out of interest, were your tests in IE on the native .getElementById()? or was it a patched version to overcome the IE bugs with this method?

    see bug here:

    http://webbugtrack.blogspot.com/2007/08/bug-152-getelementbyid-returns.html

    Getting the result fast in IE is no good to anyone if it is the WRONG result!

    April 12, 2008 1:04 pm

  2. admin:

    @Sam,

    To answer your question, the getElementById was the native implementation. Although I’m not sure what prototype does with that situation, so the $ function could be a patched version. I used the latest stable version of prototype in this example (1.6.0.2).

    Thanks for pointing out the bug, I was aware of it, but I usually just work around it by making sure my names and ids are all unique, although I never really thought of the meta description tag as pointed out by the bug.

    April 12, 2008 1:35 pm

Trackback URI | Comments RSS

Leave a Reply