jQuery Performance Rules

Bookmark and Share

Apr ‘09 8

Once upon a time, all we needed to worry about was reducing Bytes and Requests and playing around with load order to make things faster. Nowadays, we are increasingly impacting one more major component in performance – CPU utilization. Using jQuery and other frameworks that make selecting nodes and DOM manipulation easy can have adverse affects if you’re not careful and follow some simple practices for reducing the work the browser has to do.

  1. Always Descend From an #id
  2. Use Tags Before Classes
  3. Cache jQuery Objects
  4. Harness the Power of Chaining
  5. Use Sub-queries
  6. Limit Direct DOM Manipulation
  7. Leverage Event Delegation (a.k.a. Bubbling)
  8. Eliminate Query Waste
  9. Defer to $(window).load
  10. Compress Your JS
  11. Learn the Library

1. Always Descend From an #id

The fastest selector in jQuery is the ID selector ($('#someid')). This is because it maps directly to a native JavaScript method, getElementById().

Selecting Single Elements

<div id="content">
	<form method="post" action="/">
		<h2>Traffic Light</h2>
		<ul id="traffic_light">
			<li><input type="radio" class="on" name="light" value="red" /> Red</li>
			<li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li>
			<li><input type="radio" class="off" name="light" value="green" /> Green</li>
		<input class="button" id="traffic_button" type="submit" value="Go" />

Selecting the button like this is slower:

var traffic_button = $('#content .button');

Instead, select the button directly:

var traffic_button = $('#traffic_button');

Selecting Multiple Elements

Once we start talking about selecting multiple elements, we are really talking about DOM traversal and looping, something that is slow. To minimize the performance hit, always descend from the closest parent ID:

var traffic_lights = $('#traffic_light input');

2. Use Tags Before Classes

The second fastest selector in jQuery is the Tag selector ($('head')). Again, this is because it maps to a native JavaScript method, getElementsByTagName()


<div id="content">
	<form method="post" action="/">
		<h2>Traffic Light</h2>
		<ul id="traffic_light">
			<li><input type="radio" class="on" name="light" value="red" /> Red</li>
			<li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li>
			<li><input type="radio" class="off" name="light" value="green" /> Green</li>
		<input class="button" id="traffic_button" type="submit" value="Go" />

Always prefix a class with a tag name (and remember to descend from an ID):

var active_light = $('#traffic_light input.on');

Note: 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');

Along the same lines, it is redundant to descend from multiple IDs:

var traffic_light = $('#content #traffic_light');

3. Cache jQuery Objects

Get in the habit of saving your jQuery objects to a variable (much like our examples above). For example, never (eeeehhhhver) do this:

$('#traffic_light input.on).bind('click', function(){...});
$('#traffic_light input.on).css('border', '3px dashed yellow');
$('#traffic_light input.on).css('background-color', 'orange');
$('#traffic_light input.on).fadeIn('slow');

Instead, first save the object to a local variable, and continue your operations:

var $active_light = $('#traffic_light input.on');
$active_light.bind('click', function(){...});
$active_light.css('border', '3px dashed yellow');
$active_light.css('background-color', 'orange');

Tip: Since we want to remember that our local variable is a jQuery wrapped set, we are using $ as a prefix. Remember, never repeat a jQuery selection operation more than once in your application.

Bonus Tip – Storing jQuery results for later

If you intend to use the jQuery result object(s) in another part of your program, or should your function execute more than once, cache it in an object with a global scope. By defining a global container with jQuery results, we can reference them from within other functions:

// Define an object in the global scope (i.e. the window object)
window.$my =
	// Initialize all the queries you want to use more than once
	head : $('head'),
	traffic_light : $('#traffic_light'),
	traffic_button : $('#traffic_button')

function do_something()
	// Now you can reference the stored results and manipulate them
	var script = document.createElement('script');

	// When working inside functions, continue to save jQuery results
	// to your global container.
	$my.cool_results = $('#some_ul li');
	$my.other_results = $('#some_table td');

	// Use the global functions as you would a normal jQuery result
	$my.other_results.css('border-color', 'red');
	$my.traffic_light.css('border-color', 'green');

4. Harness the Power of Chaining

The previous example can also be accomplished like this:

var $active_light = $('#traffic_light input.on');$active_light.bind('click', function(){...})
	.css('border', '3px dashed yellow')
	.css('background-color', 'orange')

This allows us to write less code, making our JavaScript more lightweight.

5. Use Sub-queries

jQuery allows us to run additional selector operations on a wrapped set. This reduces performance overhead on subsequent selections since we already grabbed and stored the parent object in a local variable.

<div id="content">
	<form method="post" action="/">
		<h2>Traffic Light</h2>
		<ul id="traffic_light">
			<li><input type="radio" class="on" name="light" value="red" /> Red</li>
			<li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li>
			<li><input type="radio" class="off" name="light" value="green" /> Green</li>
		<input class="button" id="traffic_button" type="submit" value="Go" />

For example, we can leverage sub-queries to grab the active and inactive lights and cache them for later manipulation.

var $traffic_light = $('#traffic_light'),
	$active_light = $traffic_light.find('input.on'),
	$inactive_lights = $traffic_light.find('input.off');

Tip: You can declare multiple local variables by separating them with commas – save those bytes!

6. Limit Direct DOM Manipulation

The basic idea here is to create exactly what you need in memory, and then update the DOM. This is not a jQuery best practice, but a must for efficient JavaScript. Direct DOM manipulation is slow. For example, if you need to dynamically create a list of elements, do not do this:

var top_100_list = [...], // assume this has 100 unique strings
	$mylist = $('#mylist'); // jQuery selects our <ul> element

for (var i=0, l=top_100_list.length; i<l; i++)
	$mylist.append('<li>' + top_100_list[i] + '</li>');

Instead, we want to create the entire set of elements in a string before inserting into the DOM:

var top_100_list = [...], // assume this has 100 unique strings
	$mylist = $('#mylist'), // jQuery selects our <ul> element
	top_100_li = ""; // This will store our list items

for (var i=0, l=top_100_list.length; i<l; i++)
	top_100_li += '<li>' + top_100_list[i] + '</li>';

Even faster, we should always wrap many elements in a single parent node before insertion:

var top_100_list = [...], // assume this has 100 unique strings
	$mylist = $('#mylist'), // jQuery selects our <ul> element
	top_100_ul = '<ul id="#mylist">'; // This will store our entire unordered list

for (var i=0, l=top_100_list.length; i<l; i++)
	top_100_ul += '<li>' + top_100_list[i] + '</li>';
top_100_ul += '</ul>'; // Close our unordered list


If you do the above and are still concerned about performance:

  • Give jQuery’s clone() method a try. This creates a copy of the node tree, which you can manipulate “off-line” and then insert back in when you are ready.
  • Use DOM DocumentFragments. As the creator of jQuery points out, they perform much better than direct DOM manipulation. The idea would be to create what you need (similar to what we did above with a string), and use the jQuery insert or replace methods.

7. Leverage Event Delegation (a.k.a. Bubbling)

Unless told otherwise, every event (e.g. click, mouseover, etc.) in JavaScript “bubbles” up the DOM tree to parent elements. This is incredibly useful when we want many elements (nodes) to call the same function. Instead of binding an event listener function to many nodes—very inefficient—you can bind it once to their parent, and have it figure out which node triggered the event. For example, say we are developing a large form with many inputs, and want to toggle a class name when selected. A binding like this is inefficient:

$('#myList li).bind('click', function(){
	// do stuff

Instead, we should listen for the click event at the parent level:

$('#myList).bind('click', function(e){
	var target = e.target, // e.target grabs the node that triggered the event.
		$target = $(target);  // wraps the node in a jQuery object
	if (target.nodeName === 'LI') {
		// do stuff

The parent node acts as a dispatcher and can then do work based on what target element triggered the event. If you find yourself binding one event listener to many elements, you are doing something wrong (and slow).

8. Eliminate Query Waste

Although jQuery fails nicely if it does not find any matching elements, it still takes time to look for them. If you have one global JavaScript for your entire site, it may be tempting to throw every one of your jQuery functions into $(document).ready(function(){ // all my glorious code }). Don’t you dare. Only run functions that are applicable to the page. The most efficient way to do this is to use inline initialization functions so your template has full control over when and where JavaScript executes. For example, in your “article” page template, you would include the following code before the body close:

<script type="text/javascript>

If your page template includes any variety of modules that may or may not be on the page, or for visual reasons you need them to initialize sooner, you could place the initialization function immediately after the module.

<ul id="traffic_light">
	<li><input type="radio" class="on" name="light" value="red" /> Red</li>
	<li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li>
	<li><input type="radio" class="off" name="light" value="green" /> Green</li>
<script type="text/javascript>

Your Global JS library would look something like this:

var mylib =
	article_page :
		init : function()
			// Article page specific jQuery functions.
	traffic_light :
		init : function()
			// Traffic light specific jQuery functions.

9. Defer to $(window).load

There is a temptation among jQuery developers to hook everything into the $(document).ready pseudo event. After all, it is used in most examples you will find. Although $(document).ready is incredibly useful, it occurs during page render while objects are still downloading. If you notice your page stalling while loading, all those $(document).ready functions could be the reason why. You can reduce CPU utilization during the page load by binding your jQuery functions to the $(window).load event, which occurs after all objects called by the HTML (including <iframe> content) have downloaded.

	// jQuery functions to initialize after the page has loaded.

Superfluous functionality such as drag and drop, binding visual effects and animations, pre-fetching hidden images, etc., are all good candidates for this technique.

10. Compress Your JS

Okay, this isn’t jQuery related, but I had to include it. There is a tendency to make JavaScript functions and variables overly descriptive, which is essential for developers but irrelevant to users. No more excuses, it’s time to build JS compression into our workflows. Comment the heck out of your code, and run it through a compression tool before launching to production. Use YUICompressor to squeeze out wasteful bytes from your code. In our experience, it safely compresses JavaScript as small as it can possibly get without a CPU penalty (such as Base62 encoding with Packer). Tip: For maximum compression in YUICompressor, always declare your variables (e.g. var my_long_variable_name;).

11. Learn the Library

Print out this jQuery 1.3 cheat sheet, and make it a goal to eventually understand what each function does. If you find yourself repeating yourself repeating, there is probably an easier (and more efficient) way. jquery cheat sheet

Tags: ,

Bookmark and Share

64 Responses to “jQuery Performance Rules”

Leave a Reply »

  1. steve howled... April 8th, 2009 at 7:37 pm

    If you want to go EVEN faster in #6, you should do a reverse while loop, i.e., while(i–>0) where i is set to the length of the array.

    For #9, do you feel any better about this approach for DOMContentLoaded in IE? I’ve used this approach quite a lot without even the slightest touch of guilt.

    /*@cc_on @*/
    /*@if (@_win32)
    var script = document.getElementById(“__ie_onload”);
    script.onreadystatechange = function() {
    if (this.readyState == “complete”) {
    init(); // call the onload handler
    /*@end @*/

  2. Porter voiced... April 8th, 2009 at 8:42 pm

    Class selector performance has improved in 1.3.x with Sizzle, but #1 and #2 are still good general tips when you have a choice.

    In #4 I’m assuming you’re indicating that you intend to reuse $active_light elsewhere in the code, otherwise you can just collapse that all down into a single chained statement. However, I don’t believe you want the semi-colons on the ends of lines 2 and 3 in your code sample. Also, you can combine the two .css() calls into a single one using a property structure instead of name/value pairs:

    var $active_light = $(‘#traffic_light input.on’);
    $active_light.click(function(){…}).css({‘border’: ’3px dashed yellow’, ‘background-color’: ‘orange’}).fadeIn(‘slow’);

    In #7, how wasteful of you to define the toggle function twice in both examples. ;)

    As for #9: That’s only going to make people want to use it more. “You mean I can melt the processor of visitors who are using IE6? Sign me up!”

  3. Veera pontificated... April 28th, 2009 at 10:33 am

    Thanks for such a wonderful tips. Have been using JQuery for a while and these tips will surely improve my usage.

  4. lockevn voiced... April 29th, 2009 at 5:39 am

    Thanks for good tips. I will use it for our new ajax site. We learn a lot of js techniques and pattern here

  5. jQuery - Was sollte man bzgl. Performacne beachten | mysrc.de muttered... April 29th, 2009 at 6:07 am

    [...] In dem Artikel geht es darum was man beachten sollte um optimale Performance mit jQuery zu erzielen. Es werden Themen wie warum man ID als selektor nutzen sollte, oder warum man besser Tags als Klassen nehmen sollte usw. angeschnitten. jQuery Performance Rules [...]

  6. saurabh shah lessoned... April 29th, 2009 at 6:39 am

    nice one…

  7. jQuery Howto wrote... April 29th, 2009 at 7:00 am

    Great collection of performance tips. I would also recommend reading related article called: “5 easy tips on how to improve code performance with huge data sets in jQuery“.

    One more tip is while working with strings, huge strings, don’t use concatination instead join them with array’s join() method like this:

    var data = ["one", "two", "three", ..., etc.];
    var newdata = data.join(“”);

  8. Technology Related Links – Post #2 - Jason N. Gaylord's Blog barked... April 29th, 2009 at 7:07 pm

    [...] jQuery Performance Rules – ArtzStudio [...]

  9. Twitted by Putcharles sounded... April 30th, 2009 at 3:28 am

    [...] This post was Twitted by Putcharles – Real-url.org [...]

  10. Nordz proclaimed... April 30th, 2009 at 4:54 am

    For your point #6, there’s a good article explaining that point in details. Go get a look at : http://www.learningjquery.com/2009/03/43439-reasons-to-use-append-correctly

  11. andy matthews stated... April 30th, 2009 at 7:57 pm

    Psst…classes ALSO map to a native JavaScript method:

    Having said that, it’s still a proven speed boost when directly selecting an ID vs classes or even tags:

  12. Rainer quacked... May 1st, 2009 at 12:21 am

    In #3:
    Isn’t it that creating a new variable like in “var $active_light = $(‘#traffic_light input.on’);”, it just creates a POINTER from the new variable to the jQuery function? In other words: everytime I call $active_light, isn’t it that in the background $(‘#traffic_light input.on’) is used, so there is NO difference at all?

  13. ArtzStudio stated... May 2nd, 2009 at 8:53 am

    @11 andy: Unfortunately in Internet Explorer, getElementsByClassName is nowhere to be found.

    I compiled this list of best practices for my company (AOL), and our audience is currently 88% some version of IE. Unless your audience is 88% Firefox, I can not recommend using this method unless it is really needed — unless native, it is slow.

    It even looks as though IE 8 does not support getElementsByClassName. Let’s both hope this happens.

    @12 rainer: No. $active_light will contain the results of the selector function, essentially a jQuery “wrapped set” object. Think of the “wrapped set” as all the DOM nodes that matched the selection, wrapped with jQuery’s special functions (e.g. .append(), .parent(), .html(), etc.). This is how chaining works; you are acting upon the “result” each time, and never redoing the expensive “selection” part again, which is what we are accomplishing by storing the results in a variable.

  14. 雨中人 » Blog Archive » 转载【jQuery性能优化指南】 muttered... May 3rd, 2009 at 6:58 pm

    [...] 性能问题还是需要引起重视的. 在twitter上发现了<jQuery Performance Rules>这篇文章, [...]

  15. Sam Tsai thought out loud... May 8th, 2009 at 12:18 pm

    I wasn’t able to get example 7 to work (other than the missing single quote after #entryform). I’m getting no feedback from the page when I focus on the input fields’ parent element.

    In my example I’ve created a that wraps my input fields that I want to add event handlers to.


    var cell = $(e.target); // e.target grabs the node that triggered the event.

  16. ArtzStudio announced... May 8th, 2009 at 1:21 pm

    Funny, I am currently working on a project where I was trying to do the same thing.

    The JavaScript “focus” and “blur” events do not bubble, and thus it is not possible out of the box to do this with jQuery. Even their new “live” method to make delegation easier does not yet support these events. Hopefully this is something they are working on.

    I haven’t solved it yet for jQuery, but here are a few links I have open in my browser from a quick googling for later reading:

    http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html (non-jQuery solution)

    Would be happy to hear if you (or anyone reading) get/got focus and blur event delegation working with jQuery.

  17. Eric quacked... May 11th, 2009 at 9:41 am

    Awesome summary of performance tips, thanks!

  18. Jeremy said... May 20th, 2009 at 1:24 pm

    Note: Using innerHTML instead of html() can save you a lot. I love jQuery, but I was surprised and disappointed to find out just how much of an increase in performance I got out of simply using $(“#mydiv”)[0].innerHTML=”[contents]“; vs $(“#mydiv”).html(“[contents]“). Also, beware, I think there is a memory leak or some other bug in the latest version of 1.3.2 for using .html(“”) to clear a body. I found that each time i ran the same util which gathered data and repopulated into a table, using html(“”) to clear the tbody was gradually degrading performance of the rest of the function. Replacing with innerHTML=”" showed no degradation. It is hard to believe, I know, but I have tested it many times. This testing was done in FF

  19. Robin shouted... May 22nd, 2009 at 12:37 am

    wonderful article. i’ve translated it into Chinese [http://rlog.cn/350] with the URL of its original text. tks a lot

  20. Dan uttered... May 26th, 2009 at 10:51 am

    thanks for the article. these all make really good sense from a performance standpoint. one question I have is in regards to event delegation, specifically a common function like highlighting the row of a table you are currently mousing over. Almost all the scripts I have seen are selecting each row on Domready and attaching the hover() event. What would it look like if instead you used the main table as the delegator. e.g.: before is:
    var $dataTable = $(“table.datatable”);
    $(‘tr’,$dataTable).each( function() {
    var row = $(this);
    function() {
    function() {

  21. ArtzStudio voiced... May 27th, 2009 at 6:44 am

    What would happen? Give it a try and find out (and post the link to your demo here) :)

    It should technically work, however I have seen situations where you mouseover/out too quickly and the bubbling for whatever reason doesn’t fire. So essentially you might be left with table rows that still have the “over” class when you have already moused out.

    It’s worth giving it a try, as the performance benefit might be worth it since you don’t need to loop through the entire table and apply the click handlers.

  22. aaron t grogg stated... May 27th, 2009 at 8:55 pm

    thanks, Dave, now i have to go over every single line of jQuery i’ve ever written or i’ll NEVER get to sleep tonight… :-)

    truly sweet,

  23. Dan Wellman warned... May 29th, 2009 at 3:41 am

    I’m not sure number 8 will give that much of a performance boost.

    I did some experimenting using a page with 10 random jQuery methods on it (mostly animations and simple add/remove functions), then another page with 5 of these on it, and another page with the other 5 on it.

    In the page with all 10 functions I then tested using $(function() {}) as a benchmark, as well as the method you describe in section 8, as well as a similar method to section 8 but adding the functions to the jQuery namespace with .extend() instead of a custom namespace.

    I then repeated exactly the same code on the other pages (with 5 each of the 10 overall functions), so that on the other pages there were at least 5 functions that were redundant.

    I was unable to find any difference between all three methods.

    Being slightly surprised by this, I had a discussion with a member of the jQuery UI dev team and explained what I was doing and asked their opinion.

    Their response was that Sizzle/jQuery is super, ultra, uber optimised and wastes almost nothing when looking for selectors that don’t exist.

    Namespacing is good for super-separation and protection of your code (preventing funcs from being overwritten, not protecting them from view of course), but probably won’t give you and performance increase :)

  24. Karl Swedberg uttered... May 29th, 2009 at 4:29 am

    @Dan, I think the performance benefit is going to be negligible there if you have a large number of rows, since you’re still binding the mouseenter/mouseleave events to every single row. If you want to try event delegation, you could do something like this:

    $(document).bind('mouseover mouseout', function(event) {

  25. Vincent Voyer squawked... May 29th, 2009 at 4:44 am

    Don’t use this :
    “If you intend to use the jQuery result object(s) in another part of your program, or should your function execute more than once, cache it in an object with a global scope.”

    Structure your code to avoid using global variables, because it’s slow, hard to read and can cause a lot of conflicts with too much use.

    Also #6:
    for long loops with concatenations (>500 times), use an array of strings and not the += method as explained here http://www.softwaresecretweapons.com/jspwiki/javascriptstringconcatenation. It will really boost the execution time on IE.

  26. Porter warned... May 29th, 2009 at 2:53 pm

    @Dan: The modified equivalent of your code snippet above would be this:


    I’ve knocked up a quick demonstration of the concept here: http://www.g9g.org/examples/bubbling.html

  27. Andreas Lagerkvist hazarded... June 7th, 2009 at 5:45 pm

    Great read. Your explanation of modular JS is scarily close to how I’ve implemented it in my home-made web app framework.

    Here’s an example of the contact-module’s JS. I use run() rather than init() though, been thinking about changing that.

    I do however include all my JS in one single file right before the closing body-tag (one of Yahoo’s 13 rules for a faster web site) and automatically run the run()-method on modules that are currently in the dom (looking for divs with ids).

  28. Charlotte Homes twisted... June 7th, 2009 at 6:01 pm

    … you lost me along the way here, but I dig speed!!

  29. John P muttered... June 8th, 2009 at 9:17 am

    Quick question on using the cache. I store a jQuery object ($remove=$(‘img.remove’);) in global space at document(ready). Later in the script, I use an AJAX get call which removes one of the images with that class, reloads the div container including a callback function to get the number of items ($(‘img.remove’).length). Can I call $remove in the callback function considering the DOM changed after I stored the object?

  30. Cory McHugh lessoned... June 19th, 2009 at 9:30 am

    Great article and I appreciate the tips. I love pages like this! When someone takes the time to clearly delineate concepts like this, and then takes the extra step of providing testable examples, it really buoys the whole community of developers! So two thumbs wayyyy up! Educating and providing valuable discussion is priceless.

    One suggestion that I would like to see, is if you left the “Do This because it is good” examples in green like they currently are, but then your examples of “Don’t do this because it is bad” type examples, you could set the background color to those code blocks to be pink or red. http://www.javascripttoolbox.com/bestpractices/ has a page similar to this for general javascript (not jquery specific), and it is a great way to contrast good ideas vs. bad ideas. Or, for accessibility for color blind users, maybe you could have one with a border of dashes, and then the other with a border of dots or something.

    Another thing that I am looking forward to is a web service that allows you to speed test javascript code in a variety of js engines (chrome vs firefox vs internet explorer for example). I think Adobe is working on something like this, and hopefully some other smart people are as well. These tips probably apply generally well for most engines, but it might be interesting to see how much of a difference it makes in the various flavors. I love to optimize, but sometimes I also find it useful to brute-force ham-fist duct-tape code if the performance change is very slight, and it is far easier to do it in a less-optimized manner. (for small prototypes and pages that are probably going to go away, for example.)

  31. Vivek Pohre wrote... June 25th, 2009 at 8:08 am

    Just an alternate thought: We can also attach our objects or variables to the “$” object which is also global in scope. This way we can save 5 characters to write = “$” instead of “window”.

    Referenced to the below mentioned topic:
    // Define an object in the global scope (i.e. the window object)
    window.$my =
    // Initialize all the queries you want to use more than once
    head : $(‘head’),
    traffic_light : $(‘#traffic_light’),
    traffic_button : $(‘#traffic_button’)

  32. Javascript森林 » jQuery性能优化指南 notified... July 3rd, 2009 at 6:15 pm

    [...] 性能问题还是需要引起重视的. 在twitter上发现了<jQuery Performance Rules>这篇文章, [...]

  33. jQuery性能优化指南 | JoyJS博客社区-互联网信息技术交流平台 announced... July 11th, 2009 at 8:36 pm

    [...] 性能问题还是需要引起重视的. 在twitter上发现了<jQuery Performance Rules>这篇文章, [...]

  34. jQuery Performance Rules - Best Practices for Speeding Up jQuery « Netcrema - creme de la social news via digg + delicious + stumpleupon + reddit voiced... July 12th, 2009 at 2:42 am

    [...] jQuery Performance Rules – Best Practices for Speeding Up jQueryartzstudio.com [...]

  35. Items of interest » Blog Archive » Bookmarks for July 11th from 17:47 to 17:47 uttered... July 12th, 2009 at 3:12 am

    [...] jQuery Performance Rules – Best Practices for Speeding Up jQuery – [...]

  36. Jeremy Chone uttered... July 16th, 2009 at 12:03 pm

    Thanks for taking the type to share those. I am doing most of them, except of the $(window) one. Timing is perfect since I was asking myself how I can optimize my non-UI layout jQuery.

  37. Andrew announced... July 16th, 2009 at 8:45 pm

    Makes me wonder about other choices that might make minor differences. For example:

    Do this?
    Or this?
    $(‘select’, $node);

    How about this?
    name = $(this).attr(‘name’);
    isActive = $(this).hasClass(‘active’);
    Versus this?
    $node = $(this);
    name = $node.attr(‘name’);
    isActive = $node.hasClass(‘active’);

    It’s probably negligible, but if one turns out to be 1% better why not use it?

  38. Разгоняем jQuery. Часть 1 | Строительство коттеджей reckoned... July 18th, 2009 at 11:22 pm

    [...] jQuery Performance Rules [...]

  39. jQuery性能优化指南 (转载) | 张经纬的博客 shouted... July 24th, 2009 at 11:10 pm

    [...] 性能问题还是需要引起重视的. 在twitter上发现了<jQuery Performance Rules>这篇文章, [...]

  40. Tom hazarded... August 4th, 2009 at 2:48 pm

    Say I have the following:
    var nav_x1 = $(“#item1″, divnavrow).parent(“a”).html(“item1 text”);
    var nav_x3 = $(“#item3″, divnavrow).parent(“a”).html(“item3 text”);
    var nav_x5 = $(“#item5″, divnavrow).parent(“a”).html(“item5 text”);


    How can I speed up my jquery specifically by combing the 3 appends into a single append. When I try to combine into a single append using a variable to encompass the 3 items, I end up getting an error, [object] gets written out to the page. Any help…?

  41. Optimizar el rendimiento en scritps jQuery | Cristian Gonzalo Arenal reported... August 6th, 2009 at 4:32 pm

    [...] es una novedad, pero si que es una novedad el que no lo uso de la forma más correcta. Por lo menos así lo ven la gente de ArtzStudio, que nos muestran una serie de indicaciones con el fin de optimizar el uso del CPU el usuario [...]

  42. David lessoned... September 27th, 2009 at 9:12 pm

    I’m using the selectable plug in to select ranges of cells in a table 30 columns by 50 rows. It takes about 50 seconds in IE8 just to apply the selectable class to every cell onload using the following statement:


    Is there any way to speed this up?

  43. Twitted by estebansaiz blurted... October 5th, 2009 at 10:13 am

    [...] This post was Twitted by estebansaiz [...]

  44. Twitted by brian_fluid stuttered... October 5th, 2009 at 10:21 am

    [...] This post was Twitted by brian_fluid [...]

  45. Twitted by JoBroot posted... October 5th, 2009 at 2:17 pm

    [...] This post was Twitted by JoBroot [...]

  46. Bart proclaimed... October 5th, 2009 at 4:48 pm

    Thanks for some nice tips.

    Regarding the subqueries, I wonder which way is faster:
    var $traffic_light = $(‘#traffic_light’),

    $red = $traffic_light.find(‘.red’)
    $red = $(‘.red’, $traffic_light)

    I usually use the second one, with context.

  47. Robert wrote... October 31st, 2009 at 10:27 am

    Thanks for the great post. Was exactly what I was looking for.

  48. Matthew Sweet thought out loud... November 5th, 2009 at 2:59 pm

    ‘nother tip, not related to any of the rules.

    If you’re enumerating over a an array, use a natve for/in loop, not $.each. It’s must faster.

  49. ArtzStudio proclaimed... November 14th, 2009 at 8:46 am

    @Bart – They’re actually the same thing when you dig into the code, so I think it comes down to your preference. A fun thing to try is using Firebug and its Breakpoint feature, so you can peak under the hood at what jQuery is doing. It’s sometimes enlightening.

  50. Erik Kallen quacked... November 27th, 2009 at 5:00 am

    The article is good, but your example for binding to parent is bad. The focus event is one of those that do NOT bubble. Replace it with another event that does.

  51. zsiswick hazarded... December 4th, 2009 at 4:03 pm

    Thank you for the thorough article. I have had performance concerns with using jQuery on a larger production website, and I will be utilizing some of the strategies you outlined moving forward. Adding bookmark.

  52. ArtzStudio muttered... December 4th, 2009 at 6:33 pm

    @Erik – thanks, I can’t believe I did that.

  53. Paul Irish announced... January 15th, 2010 at 8:49 am

    Great rules Dave, these have helped a lot of developers.
    I have some more stuff about selector optimization and some other goodies in my talk on jQuery Anti-Patterns for Performance:

  54. buy r4 ds sounded... January 23rd, 2010 at 9:26 am

    Nice catch Joseph – I had meant that to use a jQuery selector for that ID. But that’s news to me on being able to pass document.getElementById(‘blah’) to the jQuery context, seems like that could be useful. Do you have any idea whether it is better performance-wise to do that rather than $(‘blah’).find(‘blah’)?

  55. Mads Jensen reported... January 29th, 2010 at 12:09 pm

    Good learning experience on getting my jquery scripts perform even better! Good job!

  56. Nei stuttered... March 18th, 2010 at 1:39 pm

    Thanks for the great post.
    I had most of this questions, thank you so much!

  57. olivvv tipped... April 12th, 2010 at 6:40 am

    the “use sub-queries” advice is not always true. See for instance example 6 and 7 here :

  58. Alex muttered... June 18th, 2010 at 6:32 am

    Thank you for the great tips! But I have a problem with “Leverage Event Delegation”. I am building a RIA and I am using Drupal with jQuery for that. I have a big table (really big … with around 10k cells) and also big cpu performance problems on old computers (P3s and P4s … client’s computers that I can not decide change them). I am almost sure that this problems are from the binding of different events to each cell (hover, click and dblclick) and I tried your approach to this. My problem mainly is with hover. I tried to bind hover event to the parent (the table which contains the tds) but when I hover a cell it toggles only once and it does not toggle back when the mouse is leaving cell’s region. I know for a fact that happens because I bind the action to the table and not to the cell so the browser will act when I hover out of the table and not the cell. What would your approach be to this problem?


  59. Bas touted... December 6th, 2010 at 4:07 pm

    There’s always a good mood while learning something new :)
    Some points were new to me, so, thanks a lot for sharing/explanation. (e.g. 7).

  60. dale howled... January 22nd, 2011 at 8:18 am

    for #6, reiterating steve’s point is also very important – less statements for the script to go through. You can also decrement a for loop and cache your length argument outside the loop. if you do decrement, and order matters on your array, just do a .reverse() on the array before running through it. also, instead of doing string manipulation, you can also push items into an array and then .join(”) them:

    var top_100_list = [...], // assume this has 100 unique strings
    $mylist = $(‘#mylist’), // jQuery selects our element
    top_100_ul = [''], // This will store our entire unordarered list
    len = top_100_list.length; // cache the length

    for (; i–;) { // must have the semi colons like a normal for loop
    top_100_ul.push(” + top_100_list[i] + ”);
    top_100_ul.push(”); // Close our unordered list

    if i recall correctly, doing a push to an array is much faster than concatenating a string for IE. I’m not sure if that is the case for IE9 though. But i think the opposite is true when it comes to FF and Webkit – string manipulation actually is slightly faster than pushing to an array.

  61. Punkchip | Front-end developer essentials – 5 tips for efficient jQuery exacted... June 16th, 2011 at 6:56 am

    [...] jQuery Performance Rules [...]

  62. pranav howled... July 22nd, 2011 at 10:24 am

    Very nice post , I liked subqueries and tagging before classes , it comes very handy. but learning the library is crucial.

  63. John Snow thought out loud... August 18th, 2011 at 12:33 am

    Great and incredibly useful tips… I’m currently using Mootools, but the principals are definitely the same. Thank you!

  64. Andrew Gates blurted... February 20th, 2012 at 1:59 pm

    Still quite relevant three years after you wrote it. I’ve been on JavaScript for quite some time and I really like to see when authors are able to show the readers how the underlying JavaScript is working when they use jQuery. Good jQuery guidance is hard to find – I’ll be sure to point those who ask where to get decent information here. Very good read.

Leave a Reply

Please index me, experiment!

“Alright, let’s see what you got white shadow!” — Chip Douglas