How to speed up jQuery that you use everyday

  • 1
  • August 27, 2014
Douglas Radburn

Douglas Radburn

Head of Technical

jQuery is a brilliant framework that has made JavaScript accessible to developers and designers of all experience levels. It makes it quick and easy to deploy code that can do a lot, but with that in mind, it’s very easy to write really poor jQuery as a result.

This isn’t just about best practise, poor code will slow down page load speed. We’re talking code that will slow down page load speed. It might lead to unusable and unresponsive user interfaces – and then yes, the issue that the code will be so awful to follow that you should already feel sorry for the next developer who picks up the code.

So, I’d like to explore a code snippet that looks good on the outside, it definitely ‘works’ and I’ve seen in code. In fact, I’ve written it a number of times – and then, we’ll make it quicker. Once we’ve looked at the code and what we think it’s doing, we’ll delve into making it quicker and more efficient.

A quick recap on jQuery Selectors

ID Selectors

This maps directly within jQuery to the javascript call for getElementById() which means it’s very quick in all browsers.

Tag Selectors

This maps directly within jQuery to the javascript call for getElementsByTagName() which means it’s also very quick in all browsers.

Class Selectors

The speed of selecting by class name can vary depending on your browser. getElementsByClassName() wasn’t implemented in Internet Explorer until version nine, for example. Older browsers have to load in the DOM and practically scrape it to parse for class names – which is decidedly slower.

Attribute Selectors

Unfortunately, for attribute selectors, there was never a direct javascript call, so the only thing that jQuery could do initially is search through the entire DOM.

However, with modern browsers, there is support for querySelectorAll() and this performs very well.

Pseudo Selectors

Pseudo-selectors can be very slow as the selector has to be run against everything in the DOM (or the search area at least). querySelectorAll() does speed this up slightly, but it’s still not advised if it can be avoided. If it can’t be avoided, combine it with any other selectors that can narrow down the search area (like below).

Let’s have some examples…

Let’s take a look at matching all of the p elements within a div with an ID of #mydiv.

You might have some code like:

The code above, does the job. Does it do it well?

Given the recap of code above, you’d be forgiven for thinking that this maps to getElementById and then getElementsByTagName. However, our code isn’t doing that – it’s doing a full DOM parse looking for the elements. We haven’t told jQuery in an elegant enough way what we want to do.

A better way…

The question is now, how can we tell jQuery to grab the #mydiv element, and THEN find the p element? We can achieve this using the find() method.

find() is much like children() – except that children() only transverses a single level down the tree. So, if we had a structure that contained p elements within an li for example, they wouldn’t be found with children(). I think it’s a shame that jQuery doesn’t behave this way internally, afterall, our original example looks like it should react in this way.

Our final jQuery would look like this:

Let’s talk about caching and chaining

Another tip for speeding up your jQuery is to harness localised element caching and chaining.

In the vast majority of cases, whenever jQuery does something to an object, it returns the object itself via a fluent interface. This means that you can “chain” commends together – making your code shorter and, jQuery quicker.

Let’s look at an example:

Here, we’re telling jQuery to constantly transverse the DOM to find the object in question before doing something with it. We mentioned earlier that jQuery maps this directly to the native javascript getElementById. which means it’s quick. What would be quicker though, is if we got the object and then just worked on the object directly instead of going to find it again each time.

There are times when you might want to do this, for example, if AJAX is still updating elements etc, but in the vast majority of cases (like that above), you’re not waiting for something like that.

A quick way

A quick way of doing this would be to assign the object to a variable and then work on that variable.

Here, we’re working directly on an object stored in memory, rather than asking jQuery to go back through the DOM and find the object again.

Even Quicker

An even quicker way of interacting with the object would be to use chaining. We don’t even need to reference a variable then – through the fluent interface, jQuery keeps track of the object it’s working on.

If you’re looking to speed up your jQuery even further, look to group any repetitive calls. For example, if you have multiple CSS modifications or addClass() calls, combine them. For example, rather than the following:

Use this:

Let’s talk about $(this)

When reviewing this post, my colleague mentioned that I should probably cover $(this). This is relevant due to the improvements and optimisations it can have to the script. For most people who know object-oriented design patterns, this is probably very familiar. Within jQuery, this is used in two contexts.

1) As a jQuery object within your own jQuery functions
2) As a DOM element within a callback function

The second is the one we’re most interested in and using it will reduce processing as much as the above.

Let’s take two code samples.

Here, we’re making jQuery scan through the DOM twice. We should really be taking advantage of $(this). So how can we improve the code?

In this example, we’re using the DOM element within the callback function (our anonymous function) to reference the jQuery object that refers to the #div element. This means that jQuery doesn’t have to scan the DOM the second time – it already references the original element.

If you’d like us to review any code on your existing site to help you improve customer interaction or page speed in general, then please get in touch with us.