Writing better jQuery code

Tips and best practices patterns to avoid common pitfalls and start writing better jQuery code


jQuery is a really useful and cool platform that allows for rich web application development with very little effort. That’s probably why it has become the popular kid in the block everybody wants to play with. It is also very accessible to developers with all levels of experience, which is fantastic in a way, but has also produced an impressive amount of code that sucks really bad all over the web.

In this post we’ll take a look at some simple yet important techniques that will make your jQuery code faster and better.

Install jQuery the right way

Installing jQuery is the first requirement to start using jQuery. But are you installing and distributing jQuery the right way?

Always install the latest version of jQuery unless you have a good reason not to. The latest version will always have bug fixes, new capabilities and enhanced performance. Include the jQuery script from the Google Developers website but also distribute jQuery alongside your app just in case the file can’t be loaded from the web. You should always add the jQuery reference at the bottom of your body. This way the page loading will seem faster in the user eyes. Here is an example

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery.1.9.min.js">\x3C/script>')</script>
</body>

If you are adding your scripts right before the closing body tag, you don’t need to add a call to document.ready() because at this point, the DOM was already loaded. What you should be doing, however, is wrapping your jQuery script with a self-invoking anonymous function, and passing the jQuery object in as a parameter to the function. The benefit of this practice is that if in the future you add another framework that also uses $ as a pointer to an object, your jQuery code will play nice with it.

(function($) { 
// write your code here
})(jQuery);

Finally, always combine and minify your scripts to reduce download sizes and to increase loading speed. There are several tools out there for this, and if you’re doing server side development your platform will most likely have tools for doing this automatically.

Optimize your selectors

This is probably the most important thing to take care of when working with jQuery. Selections can be made in many ways, but not all of them offer the same performance advantages. In the worst case, whenever you select an object from the DOM, jQuery has to scan through all the elements in the objects tree and try to match what you’re searching for to the element that is being scanned. This can be really slow if you have a complicated DOM structure and a lot of operations.

In most of the cases we can achieve much better performance by optimizing the selector that we are going to use. As a rule of thumb, id is always better than element, and element is always better than class. Pseudoclasses and Attributes are not even welcome in selectors. Use them only if you have absolutely no choice. The reason for this is that id and element selectors are backed by native JavaScript operations whereas classes not so much.

Always try to construct your selectors in a left to right model. This is less specific in the left side, more specific in the right side. For example

$(‘.navbar-nav li p’);

This will target all the p tags inside li tags inside an element with the navbar-nav class.

Give your selectors a context

If you use a context for your selectors, the search space is reduced, making your selector much more efficient. For example, let’s say you have a div with an id of main, and you want to target all the a elements with a class of active. While you could just select the elements directly, this would make jQuery search for them in the entire DOM. If you select the div element using its id instead and then find the a elements descending from there, the selector becomes much more efficient.

$(‘#main a.active’); // slow
$(‘#main’).find(‘a.active’); // fast

Always cache selected elements

Caching means that we store the selected element in a variable for later use. This way we don’t need to search for it in the DOM again. When we chain methods, we are leveraging the cached object too, as well as improving code size and readability, so do as much caching and chaining as possible.

$actives = $(‘a.active’).show().fadeOut(); // chaining methods
$actives.css('opacity', 0.5); // re-using the cached element

Use .find() and .children()

We already saw how to use .find() when we have a context for our selector. Actually, there is more than one way of creating a context for your selector, but find() and children() are the fastest ones.

The difference between them is that children() will only look at the direct children of the specified element, and find() will look at the entire tree, including grandchildrens and so on.

Here is a test that compares the performance of the different options.

Efficient DOM manipulation

The DOM is not a database, and even though jQuery allows us to treat it as such, there’s a cost associated to it. Insertions and update operations are particularly more complicated than finding elements in the DOM, and can be very slow.

Detach elements from the DOM

One good approach for improving DOM manipulation is calling .detach() in the element being modified. This will temporary remove the element from the DOM while retaining its properties to allow you to reinsert it later.

Efficient append operations

If you are attaching lots of elements to the DOM, it’s better to create one single element containing all the attachements and then append that to the DOM in a single operation. Another operation to consider here is string concatenation, which is not very efficient. The most efficient way is to push all your elements to a temporary array, and then calling join on the array to create one single string containing all the elements, and finally appending that to the DOM in a single operation. Here is an example:

var arr = reallyLongArray;
var temp = [];
var i = 0;
var length = arr.length;
for (var a = 0; a < length; a++) {
temp[i++] = '<tr><td name="pieTD">';
temp[i++] = arr[a];
temp[i++] = '</td> </tr>' ;

}
$('table').append(temp.join(''));

Leverage Event Delegation

Event delegation is a powerful concept that can make your events perform much better. Let’s say you have a table with 1000 td elements, and you want to add a click event to the td elements. You could do this:

$('table').find('td').on('click', function(){
$(this).slideUp();
});

The problem with this approach is that you are attaching 1000 event listeners to the DOM. There is a better solution using event delegation, which attaches the click to the table itself and then specifies the elements that should be bound to the event. Example:

$(‘table’).on(‘click’, ‘td’, function(){
$(this).slideUp();
});

There’s a big difference between these approaches.

Use jQuery only if you need it

Many developers tend to forget that jQuery is JavaScript. If you need the id value of an element, you can get it using plain ol’ JavaScript. Creating a jQuery object has an associated cost that you can avoid if you use vanilla JavaScript. The same goes for loops. You will be better off by using native JavaScript for loops than $.each() loops. The bottom line is native functions are always faster than their counterparts.

With great power comes great responsibility — Uncle Ben