Found Code: JavaScript getElementById, Performance, and the $ Function
Disclaimer: Check the date! This post was written way back in . If there are technical things in here, they're more than likely outdated, or there may be better ways to do them by now. You've been warned.
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):
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:
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</span> 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.