jQuery Performance Tips

Introduction
I've been working with jQuery for a while now and I have to say I'm very impressed. It really does live up to the headline, 'write less do more' and allows developers to become productive very quickly. This kind of immediate productivity is great but there is the potential for inexperienced jQuery developers to write code that performs poorly.
This was recently brought to my attention while working on a project where we were targeting IE8. Running on Chrome our application was perfectly responsive, but this was not the case when we switched to IE8. It’s well known that the JavaScript engine used by IE8 is considerably slower than that of the latest generation browsers, but I was still surprised by the difference in performance. The application was noticeably slower and the decreased performance had a significant impact on user experience.
After performing a few code reviews I put together some guidelines to help improve the efficiency of the jQuery we were writing. The changes applied were minimal, but the results were significant and we saw a considerable performance improvement. As a result the application was much more responsive and the user experience improved dramatically. There's nothing ground breaking here, just a few simple guidelines that may help others who are experiencing similar problems with older browsers

Choose the right Selector
jQuery selectors offer a convenient way to get a handle on any DOM element or group of elements. It should be noted though that not all selectors are equal,and choosing the right selector can have a significant impact on performance.

Select By Id
If possible select elements by Id, for example $("#name"). This is efficient because it uses the native DOM function getElementById. An Id is unique on the page and as a result the search ends as soon as the DOM element is found. This is not the case when searching by non unique attributes like class name.

Narrow your Searches
It's not always possible to search by Id and sometimes we need to search by some other type of DOM attribute. A common example is searching by class name as shown below.

var element = $('.myClass');

This is potentially quite expensive, especially in older browsers like IE8 that don't implement the native getElementsByClassName function, and require a full DOM search. For this kind of scenario it makes sense to narrow the search to a subset of the DOM by telling jQuery where to start searching. This improves performance by reducing the amount of DOM that is processed for a given search.
One way of narrowing the search is by specifying a context parameter with our selector - we could update our previous search to specify a starting element as follows.

var element = $('.myClass', someDomElement);

An alternative to context parameters is to use the find() function as shown below

var element = someDomElement.find('.myClass')

Both approaches are equivalent so choosing one is really a matter of personal preference. The important point is, the smaller the specified DOM element the faster the resulting search. Its therefore important to be as specific as possible when using with the Context parameter or find() function.

Cache Selectors
As mentioned above, it’s important to be aware of the overhead associated with using different types of selectors. Even selecting by Id has an associated overhead, so we should minimise where possible. You'll often see code like this

$('#someGrid').dataTable().fnClearTable();
$('#someGrid').dataTable().fnAddData(someData);
$('#someGrid').doSoemthingElse();

Here we've called the same selector 3 times. It would be more efficient to hold a reference to the selected element and work with that reference.

var dataGrid = $('#someGrid');
dataGrid.dataTable().fnClearTable();
dataGrid.dataTable().fnAddData(someData);
dataGrid.doSoemthingElse();


The performance gain using a cached selector in this instance isn't significant because we’re selecting by Id. However, if we had a similar scenario that selected by class name, then the use of a cached selector would see a significant performance improvement. As a general rule of thumb it’s a good idea to use cached selectors wherever you can. Here we can see a performance comparison between cached and non cached selectors.

Method Chaining
Almost all jQuery methods return an object allowing you to conveniently chain method calls. This makes for cleaner more concise code as seen in the examples below.

Rather than writing this...
$('#surname').addClass(".someClass");
$('#surname').css("right","-130px");
$('#surname').css("top","-15px");

We can chain the method calls like this...

$('#surname').addClass(".someClass").css("right","-130px").css("top","-15px");

As well as being cleaner and more concise, method chaining also offers a small performance benefit over individual function calls, especially when combined with cached selectors. Here you can see that method chaining is marginally faster in most cases.

Hopefully the points above will be useful to others experiencing jQuery performance issues. Please feel free to leave a comment below.

Comments

  1. Some great tips, thanks.

    Another simple tip that is easy to avoid is ensuring that you have the latest jQuery library. The jQuery guys are always releasing new versions that almost always include performance enhancements.

    jQuery themselves host the latest jQuery API. Update the src attribute within the script tag to:
    src="http://code.jquery.com/jquery.min.js"

    Its also the minified version so that an extra performance gain :)

    ReplyDelete
  2. Although this tip assumes you are happy enough with not have jQuery held locally. It may mean a feature that you now use could become deprecated in the future. Although I'd say this would be well handled and probably wouldn't break your code. At least I hope :)

    ReplyDelete
    Replies
    1. I guess hosted vs locally held jQuery could be another blog post. I may at some write a blog about that myself over at DopeyDev.com

      Apologies Brian for the shameless plug :)

      Delete

Post a Comment

Popular posts from this blog

Spring Boot & Amazon Web Services (EC2, RDS & S3)

Spring Web Services Tutorial

Health Checks, Metrics & More with Spring Boot Actuator

Spring JMS Tutorial with ActiveMQ

Axis2 Web Service Client Tutorial

An Introduction to Wiremock

Spring Batch Tutorial

Externalising Spring Configuration

Spring Quartz Tutorial