Javascript Performance

Posted by Julian Seidenberg on 13 June 2012

Julian is one of our SilverStripe developers who works with the rest of the team on large projects, as well as acting as technical lead on projects of his own. He is an American citizen who has never lived in America. He was born and grew up in Germany, studied in the UK, and is now happily living in New Zealand, whose friendly, laid-back culture and natural beauty he values.

I love using SilverStripe and Javascript to create awesome web software. I would typically create a SilverStripe CMS interface for configuring the application, then pull all the required information out of the database into a template using SilverStripe’s template language, and finally use Javascript to transform the template into a wonderfully interactive page.

However, performance can be a problem, especially in older browsers (IE6, IE7, I’m looking at you). In one major project I was involved in we discovered that pages would “hang” for 10-20 seconds in IE6, while the Javascript struggled to run. We scrambled to optimise the Javascript and managed to improve the page load time by a factor of ten. That taught me to pay special attention to Javascript performance.

This article talks about some of the optimisation techniques I have learnt. Techniques that will hopefully give you significant performance improvements for your own websites.

Golden rule: Javascript is fast, DOM is slow

Javascript code generally runs pretty quickly. The thing that causes performance trouble is whenever you hit the Document Object Model (DOM) of the page. Beware any time you query a jQuery selector, append something into the page, or bind a new listener. The monster of poor performance is lurking in the browser waiting to bite you! - Javascript performance playground

Your secret weapon to help you battle the monster is this fantastic website:

You can use it to construct your own Javascript performance tests and try them in all the browsers you need to support. You can also browse the many tests other people have previously constructed. All the optimisation techniques in this article are backed up with reference to jsperf tests. So, you don’t need to take my word for it. You can see for yourself.

1. Optimise for the slowest browser














Take a look at the above jsperf test.

The “without tag” code runs amazingly fast in Firefox (27,970 operations per second). Does that mean you should take advantage of that and write all your selectors without a tag? No.

Take a look at the data: IE6 runs 9 (nine!) operations per second running the “without tag” code and improves to 554 operations per second when running “with tag”. So, if you have to support IE6, help it along by using using tags and over-specify the jQuery selectors.

The reason iE6 is so slow is that it doesn’t have a built-in getElementByClass function. So, if you use a jQuery selector without a tag the browser has to scan through every single element on the page looking for a match.

2. jQuery Entwine is different








We like to write Javascript with Entwine. The Entwine jQuery plug-in makes it easy to attach methods to DOM elements. Check it out:

This jsperf test shows that entwine behaves differently in regards to its selectors (it uses a “delegate” binding in the background). So, if you are using Entwine, keep your selectors short and don’t specify the tags.

3. Use plan Javascript when you can






jQuery is nice, but why use it when you don’t need to? Sometimes, when you just want the “id” of an element, you can get it using plain Javascript. No need to wrap the element with jQuery. That just introduces a performance penalty for no benefit.

4. Avoid pseudo class selectors




Pseudo class selectors are very convenient and helpful. However, they are also really slow. Refactor your code to use normal classes instead of relying on pseudo-class selectors and it will run a lot quicker.

5. Chain selectors







I often see code that repeats the same selector multiple times. That is such wasted effort. The browser has to query the DOM three times for the same result. Instead, save the element in a variable. Or, better yet, take advantage of jQuery’s ability to chain method calls.

6. Avoid children() unless you only want children





This is really surprising. If you want to query sub-elements of an element, the “find” method is faster than the “children” method. You might think that because children is more specific, that would be faster. After all, it has less elements to search through. However, that isn’t the case. “Children” first needs to figure out which elements are the direct children of the parent element and that involves a depth-first search of all elements. So, effectively, “children” has to run a “find” first, then filter the results to give you only the direct children. Take home message: always use “find”, unless you specifically want “children”.

7. Use jQuery 1.7 event delegation instead of event binding











jQuery 1.7 has a fantastic new event handler called “on”. If you don’t know about it yet, read about it here:

Traditionally you might have bound an event to multiple DOM elements, but with “on” jQuery encourages you to use event delegation instead. The delegation approach means you only bind to a single element and intercept events as they bubble up the DOM tree. This saves a lot of time and makes the code run much faster.

8. Use window.load when appropriate







$(document).ready is a great way to run Javascript code once the DOM has loaded. However, sometimes there is some non-critical Javascript that can wait a while longer before running. For those cases, remember the handy $(window).load function. That runs once all elements on the page have fully loaded (including images, frames and objects). If you put some of your Javascript into the “window” function, that reduces the amount of code in the $(document).ready function, giving the appearance of faster Javascript.

9. SilverStripe Requirements combine and minify











SilverStripe has a nice feature (Requirements::combine_files) that automatically combines and minifies all Javascript code on a page. In “dev” mode the Javascript loads separately so you can read it all when debugging. But as soon as you switch to “live” mode the framework takes all the Javascript files, combines them into a single file, minifies them and includes the single file in the page.

Downloading, parsing and executing a single Javascript file is significantly faster than processing many separate ones. The code isn’t actually any faster, but it ends up running quicker. Using “Requirements::combine_files” is really easy, so there is no reason not to take advantage.

Post your comment

Note: Comments are moderated and won't show until they are approved


  • Simon,
    There is certainly a potential problem with events taking a while to fire, if you bind too many delegates/on handlers on a top-level element like "body". Doing that would mean that every event has to run through many handlers before finding the correct one, thereby slowing event processing. However, in practice, I've never found this to be a problem. I've found start-up time far more problematic than event execution time.

    Still, you make a good point, we need to be careful and bind delegate/on events to as specific elements in the DOM as possible. That mitigates the potential problem of slow event firing. So, instead of binding to "body", you would bind to "#navigation", as an example.

    You are totally correct that delegation has been part of jQuery for a long time. However, in 1.7, with the new "on" method, it has become the recommend default way of binding any event. The jQuery team substantially improved delegate performance in the 1.7 version. See this blog post:

    So, while you could write delegates before 1.7, they weren't appropriate in every situation. Now, however, you can do so as the default. The new "on" method is always the right choice :)

    Happy Javascripting,

    Posted by Julian Seidenberg, 2 years ago @candidasa4

  • I noticed that these tests only consider startup time. Have you tested the relative performance of the events actually firing compared to how they're added?

    Posted by Simon, 2 years ago @simonw

  • Actually, regarding #7, proper event delegation in jQuery has been around since 1.4.2 ( I say "proper" because there technically was event delegation since 1.3 but it hadn't found its true name yet (

    Posted by Matt, 2 years ago @webbower

RSS feed for comments on this page | RSS feed for all comments

Want to know more about the company that brought you SilverStripe? Then check out

Comments on this website? Please give feedback.