Thursday, November 09, 2006

Lessons in Javascript Performance Optimisation: 90 seconds down to 3 seconds

I've recently been optimising the guts out of a JS webapp I wrote, which was making IE crawl to a halt. I discovered this after introducing a stress-inducing data set. (Using Rails' fixtures makes light work of this; since the fixtures are Ruby templates just like the web templates, it's easy to introduce a loop to create lots of data.)

With a rather large data set (100+ items, each several fields), IE would take about 90 seconds to churn through the initial script before the user could do anything. Firefox would run the same thing in about 8 seconds, still too long for a web page, but incredibly about ten times as fast as IE. I'm wanting to avoid pagination at this stage, so first priority was to tweak performance and see if we can keep everything on the same page.

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.
PLAIN TEXT
JAVASCRIPT:
  1. function findAllItems() {
  2. <% js_array = @items.map { |item| "document.getElementById('item#{item.id}'),"}.join
  3. js_array = js_array[0..-2] if @items.length>0 # Drop extra comma at end -%>
  4. return [<%= js_array %>];
  5. }

The last step explicitly identifies all items in the class, removing the need to discover them by traversing the DOM. I wasn't really sure how much time it would save - after all, you still have to look the elements up in the DOM and assign them to the array. But when I tried it, the savings were supreme - on IE, from around 45 seconds to about 2 seconds.

I have also incorporated Dean Edwards' superb onload replacement to get the ball rolling before images are loaded. It's a neat trick and takes 5 minutes to refactor it in.

5 comments:

tuo said...

I like your blog . They are really great. Ermunterung ++ .
some new style Air shoes is in fashion this year.Do you know Air Shoes is a best . another kinds of nike air rift is better . the Puma basket will make you feel very relaxed when you play basketball.If you want to buy the Cheap puma shoes shoes ,you can buy them online. Very high-caliber and cheap puma shoes as same as you buy from the authorized store..My younger sister's long hair is always chaotic. so i presented a hair straighteners to her for Christmas last year .she were very pleasantly surprised .

tuo said...

ralph lauren polo shirts
chaussure puma
puma CAT

ed hardy clothing
ed hardy sunglasses
Ugg Boots
hair straighteners
orange CONVERSE

tuo said...

You are currently spoilt for choice Polo Shirts On Sale with the selection of current star names to get put on the back of the polo ralph lauren, with such playres as Maldini, Toni, Di Rossi, Iaquinta, Pirlo, and Canavarro to name just a few cheappolos. And three are othre rising stars who might take your fancy burbrery polos, like Rossi, Balotelli, Pazzini and Aquilani. Ralph Lauren Polo Shirts are all going to be names that you’ll hear a lot more Burbrery Polo Shirts of in the future I’m sure.

tuo said...

In spite of the fact that many critics comment on ed hardy clothing as nothing but tattoo pattrens, being full of unnecessary and useless things, ed hardy clothes is widely acknowledged that ed hardy shirts draws the most attention of both common young people as well as many Hollywood welcomed stars for its punk rock styles. In fact, in today’s world, many ed hardy t-shirtsdesigns are more or less the same with each othre, and ed hardy mens and ed hardy womens , absolutely, brings a totally new shock in the fashion world for its design being out of ordinary ed hardy sunglasses.

Sneakers hobbies said...

nice post!!
this winter choose a spyder ski clothing to help you far away cold and wrick is good choice.welcome visit our online outlet,we're not only supply high quality but also most cheap ski clothes and winter clothes.you can buy the most cheap spyder jackets ,and you buy more you will get more discount..