Last week I got to analyze a web page that spent 4.8 seconds in the onLoad event handler of a custom script file. It turned out that 2.8 seconds were consumed by applying a dynamic menu library (will blog about this one separately). The remaining 2 seconds were spent in jQuery selectors. The analysis showed that most of the selectors didn’t return any object and those that returned objects can be improved by using different selectors.
About jQuery Selectors
There are some great blog articles about jQuery Selectors and their Performance Impact. As you can see you can select elements by ID, TagName or ClassName. Depending on the select jQuery can use the native browser methods to query elements by id or tag or needs to manually iterate through the DOM in case of class names (as there is not getElementsByClassName in IE).
Analyzing the 2 seconds in my page time
The onLoad handler uses jQuery to set hide, show, change style sheets, … for certain elements on the page. Here is a code snippet:
The onLoad event handler was full of these calls. Using the free Dynatrace AJAX Edition you can see the individual $ calls that resolves the selector and the following method call in case the selector resolved at least one object. The following PurePath of the onLoad event handler not only shows me how much time was spent in those selector calls – but also how many of these actually didn’t find a single object (the lack of the following method call indicates that no object was found):
The first lesson learned from this is that most of these calls were not necessary and just caused massive overhead. If you happen to know which elements are on a page you should only resolve those objects and don’t try to resolve others. I know – having global java script files that handle different pages with different content cause a situation like this – but – do you really want to live with this overhead?
Analyzing difference in jQuery Selectors
The first problem on the analyzed page was that too many unnecessary $ calls were made. The other question that came up was why certain $ methods respond very fast (some milliseconds) where others take rather long (up to 100ms). The theoretical answer can be found in the jQuery Best Practice Blog. Coming back to my page shows me the following:
Selector by ID is the fastest using getElementById
Following image shows a selector using an ID. It uses getElementById and therefore returns very fast.
Selector by TagName using getElementsByTag
The following example selects elements by TagName and ClassName. jQuery first uses the getElementsByTagName which is a native implementation to retrieve all elements for the specified tag. jQuery then iterates through these items to filter for the ClassName.
Selector by ClassName needs to iterate through ALL DOM elements
If you use a selector by ClassName only – jQuery needs to iterate through EVERY element in the DOM as there is no native implementation for getElementsByClassName in Internet Explorer (its a different story for FireFox). Following image shows the overhead of a selector on a page with 3460 DOM Elements:
Depending on the size of your web site (number of DOM elements) you should consider the overhead of individual selector methods. Instead of selecting by classname you may want to think about using TagName and ClassName or by using unique IDs in case you only have a handful of objects on your page. Also – make sure you cache already resolved objects to avoid the overhead for subsequent resolving calls. And – last but not least – avoid calls that are not necessary. As seen in the page that I analyzed – more than 1.5 seconds of the 2 seconds can be saved by not making those calls.