Wednesday, September 27th, 2006
Lessons in JavaScript Performance Optimization
<p>Fellow Ajaxian, Michael Mahemoff, has written about an experience with optimizing JavaScript from a 90 second benchmark to 3 seconds.The hog that slowed down the system was $$(".classname") being used on a large DOM:
After some sophisticated profiling ((new Date()).getTime():D), the main culprit was revealed to be prototype's $$. It's a fantastic function, but if you try to grab all elements belonging to a certain class, and the DOM is really big, $$(".cssClassName") can be slow. *REALLY SLOW* in IE. Remedy
- Removed trivial usages of $$() - e.g. in one case, the script was using it as a simple shorthand for a couple of DOM elements, and it was easy enough to hardcode the array. i.e.
$$(".instruction") becomes [$("initialInstruction"), $("finalInstruction")]. The former notation is cuter, but unfortunately impractical on a large web page.- Introduced the unofficial selector addon. Seems to have improved performance in more complex queries, i.e. $("#knownId .message"), but doesn't seem to have affected performance of $$(".classname").
- Finally, I bit the bullet and scrapped $$(".classname") altogether. It's more work, but the script now maintains the list of elements manually. Whenever an element is added or removed, the array must be adjusted. Furthermore, even the initialisation avoids using $$(), thanks to some server-side generated JS that explicitly declares the initial list of elements belonging to the class (i.e. the list that would normally be returned by $$()). To do this, the following function is called from onload(), generated with RHTML.
JAVASCRIPT:
function findAllItems() { <% js_array = @items.map { |item| "document.getElementById('item#{item.id}'),"}.join js_array = js_array[0..-2] if @items.length>0 # Drop extra comma at end -%> return [<%= js_array %>]; }
Read more from Michael on the subject
Related Content:











It makes no sense to use $$ for such a simple selector.
document.getElementsByClassNamewill be orders of magnitude faster, especially with the recent performance optimizations (including querying by XPath if it’s available).That said, making $$ less costly is one of the major points of focus for Prototype’s 1.5.0 release.
I was just about to propose using XPath if available when I read Andrews comment. So Prototype is using XPath now. That’s great. I guess I gotta dig into the code a bit and check out what other stuff has changed since 1.4.
Interesting Finds: September 27, 2006
Well, shouldn’t $$ then use document.getElementsByClassName or XPath itself whereever possible?
See also addListenerByClassName