After some time working with C programming language in a *NIX like operating system, recently I came back again to Web Programming, mostly working with HTML, CSS and JavaScript in the client-side and other technologies in the backend area.
The current project I’ve been working on, heavily relies on jQuery and Highcharts/Highstock libraries, I must confess that at the beginning of the project my skills in the client-side were more than rusted, so, I began reading a lot of articles about new techniques and good practices to catch up very quickly, in the meantime, I start taking some notes about “best practices”1 that promotes a better use of jQuery2, I hope you find this information useful, if you have more tips or any doubt please leave your comments at the end of this article.
The first recommendation is to use the last version of jQuery, the reason is that in new releases you will find new features, and also a good amount of bugs and performance problems are fixed.
One of the benefits to work with jQuery is that it lets you find elements inside of the DOM using a syntax similar to the CSS selectors3. But, please, take into account the following considerations.
Modern browser support getElementsByClassName
, querySelector
and
querySelectorAll
directives. However, old browser versions only offer support
for getElementById
and getElementByTagName
directives. So, if you are only
targeting recent version of browsers, you might not need anything more than what
the browser offers.
One of the first tips that you need to know is this: Have preference over IDs
whenever it’s possible, even in old browser versions the search based on the ID
of an element is fast because the jQuery selector internally is converted to the
native getElementById
directive.
Avoid the tag prefix when you search for an id
:
The example above creates an inefficient query because in the first place we
traverse all the div
tags in the document, after that we look up the
myelement
id
.
In the same way, it’s redundant to nest multiple IDs in a jQuery selector:
In this case always use the most specific id
.
Also, if you want to select multiple elements, this implies that you need to
traverse all the DOM, which can generate a hit in your query performance, so,
you can avoid this negative impact descending from the most near ID element, for
example, imagine that you need to capture all the input
elements inside of a
form which id
is #myform
(yes, I know, this ID name sucks, remember, it’s
just for example purposes)
Avoid the selection of elements only by class
Avoid to select an element only by its class, the major hit in performance
occurs when your browser doesn’t support the native call
getElementByClassName
, in old versions (like IE 6/7/8 and Mozilla Firefox 2)
jQuery needs to examine each element in the page to determine where is the class
that we are looking for.
One workaround that you can use is to prefix the search with the tag element associated with the class “myclass”.
But if you are targeting only modern browsers, you better try
getElementsByClassName()
.
See: jQuery class vs. tag qualified class selector
Cache
Whenever you need to use multiple times the object returned by a jQuery selector, please store that object in a variable, avoid the following practice:
In this case you are making three queries to get the same object!, you can improve the example above as follows:
In the example above we store the object (cache) returned by the jQuery selector, after that we apply multiple methods over the same object.
Please note that the name of the local variable has the ‘$’ prefix, that’s not really necessary, but some JavaScript developers have adopted this convention that facilitates them to remember that local variable stores the results of a jQuery selector. If you prefer you can avoid this “convention”. The important thing here is that if you need to apply more than one method over the same object you must store this object in a local variable first.
Another advantage of storing objects in cache memory is that you can make sub- queries, just look at the following example:
And now we apply some queries over the unordered list:
After that we make some sub-queries:
The principal benefit of store jQuery objects in memory is that the subsequent queries don’t need to traverse again the DOM.
See: jQuery Cached Set
Method chaining
Look at the following example:
Most of the jQuery methods returns an object, that feature facilitate the method chaining over the same element:
See: jQuery chaining
Group the set of parameters over the same method
You can rearrange the previous example as this:
This way you can reduce the number of times that you need to call the same methods over the same objects. This technique create a unique literal object that combines the set of parameters that we’ll use to pass information to the method.
Minimize the use of .append(), .insertBefore() and .insertAfter()
If you want to use the .append()
method, try to avoid its use inside a loop,
in the first place you can try to generate HTML strings in memory, after your
cycle ends you can append your new string to the content instead of apply the
.append()
method inside your cycle.
Considering the following HTML structure:
Please, avoid the following pattern:
One approach can be this:
Also, you can replace the .append()
method with .replaceWith()
in some
cases:
Event delegation
Take this HTML structure as an example:
One way to manage the navigation buttons are this:
This is really terrible because you bound an event to multiple DOM elements.
You can mitigate the example above as this:
In the example above we use event delegation, this means that we need to bind to a single element and intercept events as they bubble up the DOM tree.
If the previous methods do the same at the click
event you can rearrange the
example above as this:
Remember, the idea behind event delegation is to bind to a single root element and then wait an intercept events as they bubble up the DOM tree.
Pseudo selectors
One the of the slowest jQuery selectors are pseudo and attribute selectors, so, use this selectors with precaution.
The performance hit is greater in this cases because jQuery can’t take advantage
of a native call. In modern browsers querySelector()
and querySelectorAll()
can help us.
See: id vs. class vs. tag vs. pseudo vs. attribute selectors
$.each() or $fn.each() loops
Whenever you can, try to use a plain for
(in some modern browsers forEach
is
even faster than for
) over the jQuery $.each()
function. Also, you can gain
some benefits if you cache in memory the length of your container:
See: Nesteds: JQuery each vs native JS for loop
References
- Efficient jQuery Selectors by Craig Buckler.
- jQuery Performance rules by ArtzStudio.
- jQuery best practices by Stephen A. Thomas.
- jQuery best practices by Greg Franko.
- jQuery proven performance tips & tricks by Addy Osmani.
- DOM Core
and see if this recommendations applies in your web clients, in my case, I need to provide support for some older browsers (IE 7/8/9 mostly).
sites, according to W3Techs, jQuery now runs on every second website (2012). However, currently exists a trend that states that you need to avoid jQuery when it’s possible, so, whenever it’s possible try to use native JavaScript, one example of this trend is You Might Not Need jQuery website.