Last week at Velocity we hosted a Birds of a Feather Session (BoF) and offered the attendees to analyze their web sites using dynaTrace Ajax Edition. Besides finding the typical performance problems (no cache settings, too many images, not minimized content, …) we found several sites that had one interesting problem in common: OLD VERSIONS of  JavaScript libraries such as YUI, jQuery or SPRY.

Why are outdated JavaScript Libraries a problem?

JavaScript libraries such as jQuery provide functions that make it easy for web developers to achieve certain things, e.g.: change the style of certain DOM elements. Most of these libraries therefore provide methods called $, $$ or find that allow finding DOM elements by ID, Tag Name, CSS Class Name or specific DOM attribute values.

The following is a screenshot of the Performance Report analyzing the Boston Bruins Page on msn.foxsports.com using Firefox 3.6. The Performance Report highlights 3 interesting things:

  • High Client Time (3.5 seconds in JavaScript execution until the Page was Fully Loaded)
  • 39 JavaScript! blocks that executed longer than 20ms
  • 38 calls to Spry.$$ for looking up an element by Class Name with an average of 80ms execution time
Long running CSS Class Name Lookups contribute about 80% to the Client Side Load Time
Long running CSS Class Name Lookups contribute about 80% to the Client Side Load Time

Looking up elements by class name takes 80ms on average. We see 38 calls with a total JavaScript execution time of 3 seconds. Is that normal? Even on Firefox?

The History on CSS Class Name Lookups

Looking up elements by CSS Class Name is a very popular lookup method. Browsers such as Firefox or Chrome supported this lookup natively with a method called getElementsByClassName. Older versions of Internet Explorer don’t support this.

The lack of this native implementation in IE caused many JS libraries to implement this missing feature using JavaScript. The implementations traverse through the complete DOM Tree and perform a string match on the CSS Class Name property. This works well and allows web developers to use one library that works across all browsers and browser versions. The down side of this approach is that traversing the DOM is one of the slowest operations you can do in the browser. The larger the DOM, the longer these lookup methods take to execute. I’ve blogged about this several times: 101 on jQuery Selector Performance, 101 on Prototype CSS Selectors, Top 10 Client-Side Performance Problems.

Good news is that newer versions of Internet Explorer now support the Selector API allowing JavaScript frameworks to leverage this native implementation and with that optimizing lookup performance.

Why is Spry.$$ so slow on Firefox?

Let’s get back to our example from above. We learned that newer browsers support lookups by class name natively and we also learned that Firefox, Chrome, Safari, Opera, …  had the native lookup methods implemented for a while. Does this mean that 80ms for looking up elements by class name is normal? No – it is not!! It should take a fraction of that. And here is why.

The following screenshot shows the JavaScript PurePath of Spry.$$(“.prev_label”). The PurePath shows us what happens internally in this method and why it takes 170ms for that call to complete:

Spry.$$ iterates through all DOM Elements and matches the CSS Class Name
Spry.$$ iterates through all DOM Elements and matches the CSS Class Name

Instead of leveraging the native getElementsByClassName method of Firefox the implementation of Spry.$$ uses its own implementation. Using getElementsByTagName with no specific tag name returns ALL DOM Elements – 2787 in total on that page. The library then iterates through all of these DOM elements, reading the className DOM Property and matching it against “prev_label”. Accessing 2787 DOM Properties is a costly operation and takes 170ms in that instance. That’s why Spry.$$ takes that long.

Solve this problem by upgrading your Libraries

Older versions of JavaScript libraries didn’t necessarily check the browsers capabilities for looking up DOM Elements. These libraries always used their own implementation. Newer versions of libraries do check the capabilities and take advantage of any performance enhancement they can get by using the native available implementations.

On this particular website – and also the others we looked at during the BoF session – an older version of the JavaScript library was used. Upgrading to a newer version would solve this problem. I know – upgrading is not always as easy as it sounds. Lots of testing is involved to ensure that your web site still works as expected. On the other side – speeding Page Load Time by 3 seconds by “just” updating your JavaScript library is a good argument in doing so.

Conclusion

Make sure you stay up-to-date with your library versions. Library providers are focusing a lot on performance and they make sure to optimize these libraries for the different browsers out there.

Tips and Tricks

The dynaTrace Performance Report identifies slow running JavaScript handlers and also identifies the jQuery $ method. In the case of Spry.$$ (or maybe other lookup methods that your library provides) the report won’t list these methods in the Contributor list. A little trick helps though to identify how much performance impact these methods have on your page. Simply Drill into the Hotspot View. Then type “Spry.$$” and sort by Total Sum. This will show you all invocations of Spry.$$ and how much time it takes to execute them:

Analyzing your JavaScript Lookup methods in the Hotspot View
Analyzing your JavaScript Lookup methods in the Hotspot View

Learn how to use the different views and features of dynaTrace Ajax Edition by watching the 15 available Video Tutorials