jQuery Performance Tips Cheat Sheet
I was hunting for jQuery performance tricks for a while to tune my heavy dynamic web app. After digging in a lot of articles decided to make a list of the best common performance tips. I also built a handy jQuery Performance Cheat Sheet that can be printed or placed on my desktop.
Selectors performance tips:
1. Always Descend From an #id
This is the golden rule of the jQuery selectors. The fastest way to select an element in jQuery is by ID:
$('#content').hide();
or select multiple elements descending from an ID:
$('#content p').hide();
2. Use Tags Before Classes
The second fastest selector in jQuery is the Tag selector ($(‘head’)) because it maps to a native JavaScript method, getElementsByTagName(). The best way is to prefix a class with a tag name (and descend from an ID):
var receiveNewsletter = $('#nslForm input.on');
The class selector is among the slowest selectors in jQuery; in IE it loops through the entire DOM. Avoid using it whenever possible. Never prefix an ID with a tag name. For example, this is slow because it will loop through all <div> elements looking for the ‘content’ ID:
var content = $('div#content'); // VERY SLOW, AVOID THIS
Also, DON’T descend from multiple IDs:
var traffic_light = $('#content #traffic_light'); // VERY SLOW, AVOID THIS
3. Use Sub-queries
Cache the parent object then run queries on it:
var header = $('#header');
var menu = header.find('.menu');
// or
var menu = $('.menu', header);
4. Optimize selectors for Sizzle’s ‘right to left’ model
As of version 1.3, jQuery has been using the Sizzle Javascript Selector Library which works a bit differently from the selector engine used in the past. Namely it uses a ‘right to left’ model rather than a ‘left to right’. Make sure that your right-most selector is really specific and any selectors on the left are more broad:
var linkContacts = $('.contact-links div.side-wrapper');
instead of:
var linkContacts = $('a.contact-links .side-wrapper');
5. Use find() rather than context
Indeed, the .find() function seems to be faster. But this counts more when you have a lot of traversing a page with lots of DOM elements:
var divs = $('.testdiv', '#pageBody'); // 2353 on Firebug 3.6
var divs = $('#pageBody').find('.testdiv'); // 2324 on Firebug 3.6 - The best time
var divs = $('#pageBody .testdiv'); // 2469 on Firebug 3.6
6. Harness the Power of Chaining
It’s better to chain the jQuery methods than to cache the selectors:
$('li.menu-item').click(function () {alert('test click');})
.css('display', 'block')
.css('color', 'red')
fadeTo(2, 0.7);
7. Write your own selectors
If you have selectors that you use often in your script – extend jQuery object $.expr[':'] and write your own selector. In the next example I create a selector abovethefold that returns a set of elements that are not visible:
$.extend($.expr[':'], {
abovethefold: function(el) {
return $(el).offset().top < $(window).scrollTop() + $(window).height();
}
});
var nonVisibleElements = $('div:abovethefold'); // Select the elements
DOM manipulation performance tips:
8. Cache jQuery Objects
Cache elements that you query often:
var header = $('#header');
var divs = header.find('div');
var forms = header.find('form');
9. Wrap everything in a single element when doing any kind of DOM insertion
DOM manipulation is very slow. Try to modify your HTML structure as little as possible.
var menu = '<ul id="menu">';
for (var i = 1; i < 100; i++) {
menu += '<li>' + i + '</li>';
}
menu += '</ul>';
$('#header').prepend(menu);
// Instead of doing:
$('#header').prepend('<ul id="menu"></ul>');
for (var i = 1; i < 100; i++) {
$('#menu').append('<li>' + i + '</li>');
}
10. Use object detection even if jQuery doesn’t throw an error
It’s great that jQuery methods don’t throw a ton of errors at your users, but that doesn’t mean that as a developer you should just rely on that. Even though it won’t throw an error, jQuery will have to execute a number of useless functions before determining that an object doesn’t exist. So use a quick object detection before calling any methods on a jQuery object that may or may not exist.
11. Use direct functions rather than their convenience counterparts
For better performance you can use direct functions like $.ajax() rather than $.get(), $.getJSON(), $.post() because the last ones are shortcuts that call the $.ajax() function.
12. Store jQuery results for later
Usually you have a general javascript application object – App. Keep your often used jQuery selects in it for later:
App.hiddenDivs = $('div.hidden');
// later in your application:
App.hiddenDivs.find('span');
13. Use jQuery’s internal data() method to store state
Don’t forget about using .data() function to store stuff for your elements:
$('#head').data('name', 'value');
// later in your application:
$('#head').data('name');
14. Use jQuery’s utility functions
Don’t forget about jQuery Utilities functions that can be very handy. My favorites are $.isFunction(), $.isArray() and $.each().
15. Add a JS class to your HTML attribute
Firstly, as soon as jQuery has loaded you use it to add a “JS” class to your HTML tag.
$('HTML').addClass('JS');
Because that only happens when javascript is enabled, you can use it to add CSS styles which only work if the user has JavaScript switched on, like this…
/* In your css */
.JS #myDiv{display:none;}
So, what this means is that we can hide content when JavaScript is switched on and then use jQuery to show it when necessary (e.g. by collapsing some panels and expanding them when the user clicks on them), while those with JavaScript off (and search engine spiders) see all of the content, as it’s not hidden. I’ll be using this one a lot in the future.
Events performance tips:
16. Defer to $(window).load
Sometimes it’s faster to use $(window).load() than $(document).ready() because the last one occurs before all the DOM elements are downloaded. You should test this before you use it.
17. Leverage Event Delegation (a.k.a. Bubbling)
When you have a lot of elements in a container and you want to assign an event to all of them – use delegation to handle it. Delegation provides you with the ability to bind only one event to a parent element and then check on what child the event acted (target). It’s very handy when you have a big table with a lot of data and you want to set events to the TDs. Grab the table, set the delegation event for all the TDs:
$("table").delegate("td", "hover", function(){
$(this).toggleClass("hover");
});
18. Shorthand for the ready event
If you want to save some bits on compressing your js plugin – replace the $(document).onready() event:
// Instead of:
$(document).ready(function (){
// your code
});
// you can do:
$(function (){
// your code
});
Testing jQuery:
19. jQuery Unit Testing
The best way to test a Javascript code is the human way
But, you still can use some automated tools like Selenium, Funcunit, QUnit and QMock to test your code (especially plugins). I will discuss this in another post because there’s a lot to say about it.
20. Benchmark Your jQuery Code
Always benchmark your code and see which query is slower to replace it. You can achieve this with the Firebug console. Also you can use some of my jQuery shortcut functions to make your testing easier:
// Shortcut to log data to the Firebug console
$.l($('div'));
// Get the UNIX timestamp
$.time();
// Log the execution time of a JS block to Firebug
$.lt();
$('div');
$.lt();
// Run a block of code in a for loop to test the execution time
$.bm("var divs = $('.testdiv', '#pageBody');"); // 2353 on Firebug 3.6
General jQuery performance tips:
21. Use latest version of jQuery
The newest version is usually the best one. Also don’t forget to test your code after changing your jQuery core version. Sometimes it’s not fully backward compatible.
22. Use HTML 5
The new HTML 5 standard comes with a lighter DOM structure in mind. Lighter DOM structure means less elements to traverse for jQuery and better load performance. So, switch to it when possible.
23. Append style tags when styling 15 or more elements
When styling a few elements it is best to simply use jQuery’s css() method, however when styling 15 or more elements it is more efficient to append a style tag to the DOM. This way you get rid of hard coding styles in your scripts.
$('<style type="text/css"> div.class { color: red; } </style>')
.appendTo('head');
24. Don’t load code that isn’t needed
It’s a good technique to break your Javascript code in multiple files and load them only on the pages that need them. This way you don’t load unnecessary JS code and selectors. It’s also easy to manage your code this way.
25. Keep download times to a minimum with one compressed master JS file.
After you decide what javascript files you want to load – compress them and glue in one file. This can be done automatically with open source tools like Minify integrated in your backend code or combining them and minifying with online tools like JSCompressor , YUI Compressor or Dean Edwards JS packer. I prefer the JSCompressor from the online tools.
26. Combine jQuery with raw Javascript where needed
It’s a beauty to work with jQuery but don’t forget that it’s just a framework for Javascript. So you can switch between jQuery code and raw Javascript functions where needed to gain more performance.
27. Load the framework from Google Code
Always load jQuery from Google CDN in your production application – it delivers the script fast from the user’s nearest cache location.
This way you save a server request and also the client has the chance to load the jQuery script instantly from his browser cache if he visited another site that loads the jQuery from Google CDN.
// Link the minified version by specific version <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
28. Lazy load content for speed and SEO benefits
Load chunks of your sites by Ajax to save server side loading time. You can start with the usual sidebar widgets.
Special thanks to Paul Irish, Addy Osmani, Jon Hobbs-Smith and Dave Artz for providing lots of information about jQuery performance.
Thanks to @maxescu who designed this beautiful wallpapers!
What other jQuery performance tips do you suggest?
Excellent and concrete stuff ! Really helpfull !
Really nice post. I keep catching myself using class selectors.
Also, I never knew about the “Always descend from an ID” tip, thanks!
[...] jQuery Performance Tips Cheat Sheet [...]
Awesome read. Going to make sure I put these into all future projects. Just a heads up tho, it looks like there is a code typo on #9 line 10. There is a greater than sign that should be a less than sign.
$('#header').prepend('>ul id="menu">');Should be:
$('#header').prepend('');Oops, looks like the comment does not like the code. Lets try this:
$('#header').prepend('<ul id="menu"></ul>');Thanks! Fixed.
You probably could combine #3, #8 and #12?
Also, I find #5 a bit surprising, any more results like that you’ve found? Was it just one test case?
Yes, indeed, 3,8 and 12 advice us to do the same thing – to cache the results.
As for #5 I found the .find and .ajax so far that are faster than there shortcut methods.
Great stuff! Thank you. 5) was new to me.
Question about 6): Why is it better to chain than to cache?
Thanks!
Well, maybe it’s not better but it’s faster to send the same object result from one function to another then to access it from a variable.
But I would still recommend caching in variables – it makes the code much more readable and it’s easier to test.
not sure the tip, regarding performance with .ajax vs .get/.post is really going to be necessary or noticeable… the round trip time to make a network call is going to be far greater and more noticeable than the overhead of making the extra JS function call. The .ajax is necessary sometimes, but really it means you’ll be writing more code and more code means more transfer time to some degree… meaning what’s faster the JS function call or the time it takes to load your code… Just not sure there is a clear win to using .ajax (more verbose, but sometimes necessary) to the simpler .get/.post
otherwise, awesome tips and great article. Would have liked to see an explanation to why
var linkContacts = $(‘.contact-links div.side-wrapper’);
instead of:
var linkContacts = $(‘a.contact-links .side-wrapper’);
would think a.contact-links div.side-wrapper would beat both examples?
also, were you able to measure any of these in a benchmark?
Agree, the ajax call performance will do much more overflow than the function you use. But I still use $.ajax that is more explicit and goes really nice with CoffeeScript:
$.ajax
url: ‘/’
method: ‘post’
As for the selectors, I think that it adds a new parsing level if you add the element name. So, it first searches for all the .side-wrapper than filters all the DIVs elements with this class, then searches for all the .contact-links that include that DIVs and in the end filters out all the A elements. I ran the results are the following (for 10000 runs):
$(‘.contact-links div.side-wrapper’); 516ms
$(‘a.contact-links div.side-wrapper’); 546ms
Nice post.
Can you elaborate on “object detection”. Are you referring to something like:
if($(“#foo”).length != 0){
//jquery magic
}else{
return;
}
Yes, this is perfect. I also do it in my code:
$foos = $(‘#foo’);
if($foos.length){
$foos.doomTooltip();
}else{
return;
}
Regarding inserting multiple elements into the DOM – I personally hate doing all that string concatenation, instead I rely on javascript’s built in documentFragment. DocumentFragment is a lightweight wrapper around a collection of DOM objects. You can create your dF and append all the nodes you need inserted, then insert the entire content of dF into the main DOM all at once.
var div = document.createElement(“div”);
div.appendChild( document.createTextNode(“Test div to be inserted 100 times”) );
var fragment = document.createDocumentFragment();
for(i = 0; i < 100; i++) {
fragment.appendChild( div.cloneNode(true) );
}
document.getElementById(“container”).appendChild( fragment.cloneNode(true));
DocumentFragment is fast, and has great browser support going all the way back to IE6.
Yes, indeed, DocumentFragment is a great tool. I didn’t used it yet, but I’ve read about it on John Resig’s blog. It seems that he encourages us to use it too.
Wonderful tips, I can see myself using them often!
A couple of typos:
#6: It’s better to chain the jQuery methods than to cache the selectors
#11: like $.ajax() rather than $.get()
#20: “which query”
#24: It’s a good technique to break your
#27: it delivers the script fast from the user’s nearest cache location. [remove the extraneous "S" at the end of this sentence]
Thanks! Fixed… (and ashamed about this childish typos)
Great article, but it’s rather a shame you’re not using the coding convention that cached jQuery objects should be prefixed with a $ to make them easier to spot in complex code – e.g. var $receiveNewsletter = $(‘#nslForm input.on’);
Would be great if you would adopt this convention and update all the code examples in your article to reflect it…
That’s a form of Hungarian Notation and is frowned upon by many people, not a convention.
Yes, I know Marcus, it’s a shame…
I’m doing it for a while and I hope I’ll change it into my old code. Thanks for the feedback!
Spelling: brake -> break
Thanks!
Also regarding tip #27 it’s not a good idea to load the script via HTTPS, as it’s slower (it’s encrypted) and only needed if the rest of the page is being delivered HTTPS.
Fortunately the script can be *automatically* loaded via HTTP or HTTPS depending on the current URL by using the protocol-less URL format //ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js
See http://stackoverflow.com/questions/4831741/can-i-change-all-my-http-links-to-just for more on this.
Nice!
1, 2, and 4 are a bit outdated, searching for ID hasn’t been privileged for some time now.
querySelectorAll, which ends up grabbing 99% of element lookups is almost as fast asgetElementById, same goes forgetElementsByClassName. Sizzle only servers as fallback for exquisite selectors and normalizing support for IE6/7/8.Thanks, Ricardo, for the update.
This is a great list, with the exception of #23 — If you’re going to be styling a lot of elements, you should add it to your stylesheet, and modify the DOM to use those new styles with JS, not add the CSS from javascript itself. I agree that you shouldn’t loop through a bunch of elements to add styles, but let’s not make another evil, even if it is a lesser one.
Yes, that’s true. The point is to avoid styling them one by one. Thanks for the feedback!
nice writeup overall, but there are a few points that i think are mis-leading:
- all your benchmarks are using firebug’s built-in timing functions. this is problematic for several reasons, but the biggest are that firebug uses ‘eval’ under the hood (which is very slow), and it’s just for firefox! in your code, you highlighted that the results were from firebug, but any time you’re arguing benchmarks, its better to make sure your findings are accurate. take a look at jsperf.com if you haven’t already seen it.
- #14 ‘Use jQuery’s utility functions’
i use them as well (they are super convenient), but advising people to use ‘$.each’ over a bare-metal ‘for’ or ‘for in’ loop when writing an article about performance is silly. there is no scenario where ‘$.each’ is going to beat a plain loop, as ‘$.each’ uses plain loops under the hood.
- #16 ‘Defer to $(window).load’
how can it ‘sometimes be faster to use $(window).load() than $(document).ready()’ ? the dom-ready handler fires either when ‘DOMContentLoaded’ fires (in modern browsers), or as soon as window.doScroll is available (IE). in every test i’ve ever seen, dom-ready fires much faster than the window’s ‘load’ event. dom-ready is always going to fire first, so even if its only a few milliseconds faster than the window’s ‘load’ event, i don’t understand this recommendation.
here is a perf test for jQuery.each vs. ‘for’ loops that shows the cost of the callback function overhead.
here is a perf test for dom-ready vs. window.onload. keep in mind that this isn’t testing which happens first, but which is faster to run. knowing that dom-ready happens first, and that it’s much faster to execute, i don’t get #16.
[...] no more with this guide. Link to this [...]
If you look at the first paragraph of http://24ways.org/2011/your-jquery-now-with-less-suck doing a thing like $(‘#id p’) is not the most performant way of selecting nested tags. It suggests instead of doing $(‘#id’).find(‘p’).
«the second way can be more than twice as fast as the first»
Yes, #5 is the method I use to query: $forms = $(“#my-container”).find(“form”).
[...] http://dumitruglavan.com/jquery-performance-tips-cheat-sheet/ [...]
Does anyone else leave off the last version point of their scripts, like this?:
That always retrieves the latest version of jQuery 1.5. I do it, but I’m afraid I lose the caching benefit if no one else does it…
Hm, those code snippets didn’t turn out. I’m trying to say:
script type=”text/javascript” src=”https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js”
I also use this method of including jQuery from CDN: src=”http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js”
Aren’t point 24 and 25 kind of conflicting?
You can use them both, this way you can have a bunch of glued and compressed scripts that load on demand.
sure. Must get a little tricky to manage after a while though.
We use the Yii ClientScript class to automatically glue our JS on each page. With each request we add the necessary JS files to the ClientScript stack and Yii generates for us separate bundles of glued scripts where needed.
I push all this bundles through the Minify tool after they are glued and obtain multiple bundles of glued and minified JS files
Hasn’t
.delegate()been superceded by.on()?Both of them seem to be legit.
I have read somewhere that DOM manipulation can be made faster if the element we are working on is removed from the DOM.
var myElement = $(‘#innerDiv’).remove();
// Doing all the manipulation in #innerDiv…
then $(“#outerDiv”).append(myElement );
This saves on the browser redraw.
Seems interesting. Did you do some benchmarks on it?
[...] JQuery Performance Tips Cheat Sheet (dumitruglavan.com) Like this:LikeBe the first to like this post. [...]
Hi,
First of all, great list, i know part of them but it’s helpful to see them gathered.
But i have a question :
– 24 : load your the only needed code for each page of a site
– 25 : compress files to send only one to the user
We want to do that on, for example, a site with 10 pages and on each pages the scripts that must be loaded are not the sames (some are common but not all). So how to apply your rules in this state ? Should i make 10 compressed Master JS file (one per page) or there is a thing that i’ve not understand
? with a bigger site it’s really har to manage.
Sorry if it’s the same question as Patrick but i’m not sure of your answer.
It’s my fault, i wasn’t too explicit about it.
We maintain a big, scalable site that we’ve built about 2 years ago on Yii Framework. So we use the Yii ClientScript class to automatically glue our JS on each page. With each request we add the necessary JS files to the ClientScript stack and Yii generates for us separate bundles of glued scripts where needed.
I push all this bundles through the Minify tool after they are glued and obtain multiple bundles of glued and minified JS files
It took a while to automate this process but it’s worth it.
[...] http://dumitruglavan.com/jquery-performance-tips-cheat-sheet/ Leave a Comment TrackBack URI [...]
Awesome post, thanks for all the tips.
Thanks, Frank.
Felicitari pentru tot cea ce faci cu jQuery !!!
Salutare de la Madrid de la http://www.marcelfelix.com !!!
Sper sa ai un pic de timp in cazul in care am nevoie de un profesional in JQuery.
Un cordial saludo
MF
Merci! Scrie-mi cu ce pot sa te ajut.
[...] 原文作者:Dumitru Glavan 编译:伯乐在线 – 唐小娟 [...]
[...] that is clean, efficient, and fast. That applies to jQuery development as well. This cheat sheet by dumitruglavan.com provides you with some tips you can use to improve your jQuery [...]
[...] 原文作者:Dumitru Glavan 编译:伯乐在线 – 唐小娟 [...]
[...] ORIGINAL article [...]
about the 23th tip,why not use the addClass() method ?
Sure, you can do it with addClass() too.
[...] Glavan has put together a cheat sheat for us to increase our jQuery efficiency and performance. Check it out. This entry was posted in Code, Javascript, Jquery by TheCaddy. Bookmark the [...]
[...] Texto original disponível em http://dumitruglavan.com/jquery-performance-tips-cheat-sheet/ [...]
[...] cheat-sheet met tips om jQuery performant te [...]
[...] Wallpaper Source 1024×768 | 1440×900 | 1280×960 | 1680×1050 | 1900×1200 [...]
[...] I was hunting for jQuery performance tricks for a while to tune my heavy dynamic web app. After digging in a lot of articles decided to make a list of the best common performance tips. I also built a handy jQuery Performance Cheat Sheet that can be printed or placed on my desktop. jQuery Performance Tips Cheat Sheet | Dumitru Glavan [...]
Thanks for taking the time to write this up! Very sexy stuff.
[...] jQuery performance tips Cheatsheet Wallpaper [...]
[...] jQuery performance tips Cheatsheet Wallpaper [...]
[...] jQuery performance tips Cheatsheet Wallpaper [...]
[...] jQuery performance tips Cheatsheet Wallpaper [...]
[...] jQuery performance tips Wallpaper [...]
[...] jQuery performance tips Cheatsheet Wallpaper [...]
[...] jQuery performance tips Cheatsheet Wallpaper [...]
[...] http://dumitruglavan.com/jquery-performance-tips-cheat-sheet/ Share me:Bookmark on DeliciousDigg this postRecommend on FacebookShare on google plusShare on Linkedinshare via RedditTweet about itSubscribe to the comments on this postTell a friend This entry was posted in Technology and tagged javascript, jquery by Ryan Chambers. Bookmark the permalink. [...]
[...] jQuery performance tips Cheatsheet Wallpaper [...]
[...] jQuery performance tips Wallpaper [...]
[...] Paul Irish - Paul Irish’i biliyorsunuz zaten15 Powerful jQuery Tips and Tricks for DevelopersjQuery Performance Tips Cheat SheetJQuery Performance Tips And Tricks With Addy Osmani – VideoYukarıdaki kaynaklara göre bu [...]
[...] jQuery performance tips Cheatsheet Wallpaper [...]