Speeding Up jQuery Selectors
TABLE OF CONTENTS - In This Edition:
- Choosing the right context
As you learn more about jQuery, you will start writing more complex CSS selectors and you will discover more advanced functionality. But if you are not attentive enough when using jQuery, chances are you will be writing inefficient code.
When I learned my first computer language, C++, I also learned that you could write a program using pointers (references to an address in memory) that could literally crash your computer. As a C++ programmer, it was your responsibility not to access memory you shouldn't have.
A similar type of responsibility exists when writing jQuery code, but not many web developers are aware of it. Misusing jQuery selectors in combination with literally "selecting too many things", can cause a major slowdown in processing speed of your queries.
jQuery selectors can't crash your computer. But they can possibly freeze your browser. This is mostly true when it comes to CSS selectors. The versatility and easiness with which you can access the DOM, you could be selecting too many things you don’t need to, without knowing it. By doing that you can overwhelm the system resources of your browser and slow down the functionality of your site.
The jQuery development team were aware of this situation. Therefore, they invented a solution to this potential problem. They called it context.
It's important that we minimize the number of DOM requests. Working with 5-10 nodes will probably not make a big difference. But what if you are looking to select a lot of things? By a lot, I mean 1000? Or 5000? It's not unreasonable for more advanced applications to select a large number of elements. How does this apply to jQuery?
jQuery has a plentitude of ways in which you can select elements. We already went over a decent number of selectors and the things you can do with them in the previous tutorial. The act of selecting multiple elements is not without consequences. Don't be fooled by the simplicity of jQuery selector syntax. This is where context begins to play an important role.
Let's take a closer look at the $() function offered by jQuery. Remember that you can use the dollar sign and the keyword jQuery interchangeably.
jQuery( selector, [context] )
As you can see, jQuery actually takes two parameters. The second one, indicated by square brackets [ and ] is the context, and it's optional. That is why so many people tend to be unaware of its existence.
We already know enough about the selector parameter. It's a set of elements intermixed with helper characters (such as the space, a comma, brackets or an arrow) that tells jQuery what you want to select.
You can use the nth-child keyword to select a specific element by its index location in the DOM node. You can select elements based on whether they are visible or not, by their class, by id and by their type. You can go crazy because combinations abound. Some complex combinations can also slow you down when you are walking wearing a pair of your jQuery selector shoes. The selector argument is your left shoe. The context is your right shoe. Let's see how we can use these shoes to outdance any amateur jQuery developer.
Let's now look at the jQuery way of doing these things:
$('#clockwork') // will use getElementById()
$('div') // will use getElementsByTagName()
A thinking man is now confronted by this logic: If we are to use jQuery we must stick only to these two ways of using selectors. But this will surely defy the very purpose of why that man decided to use jQuery in the first place?
Having thought this, what do we now do in order to write high performance code using the flexibility of jQuery selector variations that stretch beyond the two examples? We do this by providing the context.
By laser-targeting the area which we want to operate on, by defining the confinement of, and making specific the DOM block we will be working with, and by eliminating all the other garbage we don't need to include as part of our selection, we increase performance of our jQuery code.
Like a horde of provoked hounds, by default jQuery selectors will start their search from the very top of the DOM tree, and propagate down all branches. We can exclude some of these branches from the search algorithm entirely. By searching less space, we find what we are looking for faster. This way the browser will do less work and your program will execute faster. The hounds have less distance to travel.
The second argument of the jQuery function, immediately after the selector parameter is the context argument. It's a means to choose the branch of DOM you want to work with, ignoring all other branches in the tree of HTML elements.
The default the context is the Document. The whole DOM tree. That's what we search if we skip the context parameter. This can be a lot of markup to select, that we don't really need to. But when we pass in a reference or another $() selector, we can reduce this area significantly. All of a sudden, context becomes our best friend, and not the scary, enigmatic entity you never wanted to learn about.
Choosing the right context
Context is incredibly useful. We now know this. But before you go and start using it in your own website, consider that misusing context can lead to negative results. In order to demonstrate this, we will consider the following example.
Let's say that we have a form residing in an element whose class name is .clockwork. And we want to select all input elements that happen to be using class .orange within that form.
<div id = "clockwork">
<form id = "my_form">
<input class = "orange" id = "alex"/>
<input class = "orange" id = "delarge"/>
It's just another way of referring to an input box. Let's take a look at how we would do this without using context first:
$('.orange:visible') // select all visible input elements anywhere in DOM
And with context?
$('.orange:visible', $('.clockwork form'))
But this would be a step backward. We just doubled the amount of work for jQuery by using two complex selectors, not just one.
Instead, let's rewrite the example from above to make it fast:
Now this will cut the performance bottleneck of your jQuery selectors. The more expensive selector .orange:visible now works within the confines of a less expensive selector #my_form, in fact, the fastest you can possibly get.
The common rule to follow when speeding up the performance of your jqueries is to confine a complex selector to a less complex context.