jQuery is a “fast and concise” JavaScript library which tends to be used by everybody in almost every web project and is included by default by several frameworks. Despite having very interesting qualities (I really like its fluid chaining API and its conciseness), I don’t think using jQuery by default in all your Web projects is a good idea. I’ll explain why.
Say you’re writing a web app showing lists of items. Users can add items by clicking on a “Add” button. You want the user experience to be nice (and you want to save some of your server bandwidth) so you don’t reload the whole page each time the user adds an item: you update the only part of the document that has changed. You perform this task in JavaScript and you decide to use jQuery because every others do so.
Basically the markup we’re interested in looks like that:
There is a button, an item list and a wrapping div
element. Easy.
Your JavaScript code handling item addition is straightforward too and may look like this (I’ve deliberately simplified the item creation process, because that’s not what we’re interested in for now):
That’s only a few lines of JavaScript, that’s simple, readable and cool. You congratulate yourself for having chosen jQuery.
Well, now you want to add the ability to perform another action if a list contains at least three items. So you update your markup by adding it another button:
And you update your code accordingly:
Ok, that’s enough code for now. You can test the result here to have a better vision of what it does (just save the file on your machine and open it in your browser).
It seems fluid, clean and pretty readable, but you’ll soon see what kind of problems may arise with the jQuery programming model. Before that I just want to measure the overhead of the use of jQuery. DOM node are wrapped in a “jQuery object” allowing to use the jQuery API and to chain calls. It also transparently (and conveniently) apply functions to all nodes in the set of the jQuery object. But it also means that it adds one more level of indirection for each action. Let’s see if it costs time or not: I’ve rewritten the item-list-widget behavior in vanilla JavaScript (you can see the code here, created an HTML file with two widgets and added some JavaScript code simulating a lot of clicks on the “Add” button and measuring the execution time. Here are the results of this benchmark:
The vanilla code is about 75 times faster than the jQuery code.
From where does this slowness come from? With jQuery, you are used to write selectors each time you want to manipulate the DOM. That’s easy to write but finding the elements matching a selector means
traversing whole or part of the document tree, checking if each node matches the selector criteria or not. If you look better at the code you’ll find a selector which is very time-consuming: 'ul li'
(line 12).
This selector is not complex but has a whitespace. Each whitespace dramatically slows down DOM search. We can optimize a bit the code by removing this selector and just counting the children of the
ul
element. Just doing that divides the execution time by about 5:
“Now the jQuery code is only about 15 times slower than the vanilla code. We can optimize further the jQuery code, for example by using the children
method instead of find
but the gain would be marginal and the code would be more tightly coupled to the markup, which is a bad thing. We’ll soon explain in more details why that’s such a bad thing.
All the code used in this post (including the benchmark) is available on GitHub.
What should you remember of this first post putting jQuery to the test to build web applications?
- jQuery is not so fast, using it at large scale may dramatically slow down your application ;
- A minor change on a selector may have a significant impact on its performance.
In the next post we’ll see that as well as being slow, jQuery does not add so valuable things to your code…