Jump to content

Year

Day

24 ways to impress your friends

Fun fact: more websites are now using jQuery than Flash.

jQuery is an amazing tool that’s made JavaScript accessible to developers and designers of all levels of experience. However, as Spiderman taught us, “with great power comes great responsibility.” The unfortunate downside to jQuery is that while it makes it easy to write JavaScript, it makes it easy to write really really f*&#ing bad JavaScript. Scripts that slow down page load, unresponsive user interfaces, and spaghetti code knotted so deep that it should come with a bottle of whiskey for the next sucker developer that has to work on it.

This becomes more important for those of us who have yet to move into the magical fairy wonderland where none of our clients or users view our pages in Internet Explorer. The IE JavaScript engine moves at the speed of an advancing glacier compared to more modern browsers, so optimizing our code for performance takes on an even higher level of urgency.

Thankfully, there are a few very simple things anyone can add into their jQuery workflow that can clear up a lot of basic problems. When undertaking code reviews, three of the areas where I consistently see the biggest problems are: inefficient selectors; poor event delegation; and clunky DOM manipulation. We’ll tackle all three of these and hopefully you’ll walk away with some new jQuery batarangs to toss around in your next project.

Selector optimization

Selector speed: fast or slow?

Saying that the power behind jQuery comes from its ability to select DOM elements and act on them is like saying that Photoshop is a really good tool for selecting pixels on screen and making them change color – it’s a bit of a gross oversimplification, but the fact remains that jQuery gives us a ton of ways to choose which element or elements in a page we want to work with. However, a surprising number of web developers are unaware that all selectors are not created equal; in fact, it’s incredible just how drastic the performance difference can be between two selectors that, at first glance, appear nearly identical. For instance, consider these two ways of selecting all paragraph tags inside a <div> with an ID.

$("#id p");
$("#id").find("p");

Would it surprise you to learn that the second way can be more than twice as fast as the first? Knowing which selectors outperform others (and why) is a pretty key building block in making sure your code runs well and doesn’t frustrate your users waiting for things to happen.

There are many different ways to select elements using jQuery, but the most common ways can be basically broken down into five different methods. In order, roughly, from fastest to slowest, these are:

  • $("#id");
    This is without a doubt the fastest selector jQuery provides because it maps directly to the native document.getElementbyId() JavaScript method. If possible, the selectors listed below should be prefaced with an ID selector in conjunction with jQuery’s .find() method to limit the scope of the page that has to be searched (as in the $("#id").find("p") example shown above).
  • $("p");, $("input");, $("form"); and so on
    Selecting elements by tag name is also fast, since it maps directly to the native document.getElementsByTagname() method.
  • $(".class");
    Selecting by class name is a little trickier. While still performing very well in modern browsers, it can cause some pretty significant slowdowns in IE8 and below. Why? IE9 was the first IE version to support the native document.getElementsByClassName() JavaScript method. Older browsers have to resort to using much slower DOM-scraping methods that can really impact performance.
  • $("[attribute=value]");
    There is no native JavaScript method for this selector to use, so the only way that jQuery can perform the search is by crawling the entire DOM looking for matches. Modern browsers that support the querySelectorAll() method will perform better in certain cases (Opera, especially, runs these searches much faster than any other browser) but, generally speaking, this type of selector is Slowey McSlowersons.
  • $(":hidden");
    Like attribute selectors, there is no native JavaScript method for this one to use. Pseudo-selectors can be painfully slow since the selector has to be run against every element in your search space. Again, modern browsers with querySelectorAll() will perform slightly better here, but try to avoid these if at all possible. If you must use one, try to limit the search space to a specific portion of the page: $("#list").find(":hidden");

But, hey, proof is in the performance testing, right? It just so happens that said proof is sitting right here. Be sure to notice the class selector numbers beside IE7 and 8 compared to other browsers and then wonder how the people on the IE team at Microsoft manage to sleep at night. Yikes.

Chaining

Almost all jQuery methods return a jQuery object. This means that when a method is run, its results are returned and you can continue executing more methods on them. Rather than writing out the same selector multiple times over, just making a selection once allows multiple actions to be run on it.

Without chaining
$("#object").addClass("active");
$("#object").css("color","#f0f");
$("#object").height(300);
With chaining
$("#object").addClass("active").css("color", "#f0f").height(300);

This has the dual effect of making your code shorter and faster. Chained methods will be slightly faster than multiple methods made on a cached selector, and both ways will be much faster than multiple methods made on non-cached selectors. Wait… “cached selector”? What is this new devilry?

Caching

Another easy way to speed up your code that seems to be a mystery to developers is the idea of caching your selectors. Think of how many times you end up writing the same selector over and over again in any project. Every $(".element") selector has to search the entire DOM each time, regardless of whether or not that selector had been previously run. Running the selection once and then storing the results in a variable means that the DOM only has to be searched once. Once the results of a selector have been cached, you can do anything with them.

First, run your search (here we’re selecting all of the <li> elements inside <ul id="blocks">):

var blocks = $("#blocks").find("li");

Now, you can use the blocks variable wherever you want without having to search the DOM every time.

$("#hideBlocks").click(function() {
    blocks.fadeOut();
});
$("#showBlocks").click(function() {
    blocks.fadeIn();
});

My advice? Any selector that gets run more than once should be cached. This jsperf test shows just how much faster a cached selector runs compared to a non-cached one (and even throws some chaining love in to boot).

Event delegation

Event listeners cost memory. In complex websites and apps it’s not uncommon to have a lot of event listeners floating around, and thankfully jQuery provides some really easy methods for handling event listeners efficiently through delegation.

In a bit of an extreme example, imagine a situation where a 10×10 cell table needs to have an event listener on each cell; let’s say that clicking on a cell adds or removes a class that defines the cell’s background color. A typical way that this might be written (and something I’ve often seen during code reviews) is like so:

$('table').find('td').click(function() {
    $(this).toggleClass('active');
});

jQuery 1.7 has provided us with a new event listener method, .on(). It acts as a utility that wraps all of jQuery’s previous event listeners into one convenient method, and the way you write it determines how it behaves. To rewrite the above .click() example using .on(), we’d simply do the following:

$('table').find('td').on('click',function() {
    $(this).toggleClass('active');
});

Simple enough, right? Sure, but the problem here is that we’re still binding one hundred event listeners to our page, one to each individual table cell. A far better way to do things is to create one event listener on the table itself that listens for events inside it. Since the majority of events bubble up the DOM tree, we can bind a single event listener to one element (in this case, the <table>) and wait for events to bubble up from its children. The way to do this using the .on() method requires only one change from our code above:

$('table').on('click','td',function() {
    $(this).toggleClass('active');
});

All we’ve done is moved the td selector to an argument inside the .on() method. Providing a selector to .on() switches it into delegation mode, and the event is only fired for descendants of the bound element (table) that match the selector (td). With that one simple change, we’ve gone from having to bind one hundred event listeners to just one. You might think that the browser having to do one hundred times less work would be a good thing and you’d be completely right. The difference between the two examples above is staggering.

(Note that if your site is using a version of jQuery earlier than 1.7, you can accomplish the very same thing using the .delegate() method. The syntax of how you write the function differs slightly; if you’ve never used it before, it’s worth checking the API docs for that page to see how it works.)

DOM manipulation

jQuery makes it very easy to manipulate the DOM. It’s trivial to create new nodes, insert them, remove other ones, move things around, and so on. While the code to do this is simple to write, every time the DOM is manipulated, the browser has to repaint and reflow content which can be extremely costly. This is no more evident than in a long loop, whether it be a standard for() loop, while() loop, or jQuery $.each() loop.

In this case, let’s say we’ve just received an array full of image URLs from a database or Ajax call or wherever, and we want to put all of those images in an unordered list. Commonly, you’ll see code like this to pull this off:

var arr = [reallyLongArrayOfImageURLs]; 
    $.each(arr, function(count, item) {
        var newImg = '<li><img src="'+item+'"></li>';
        $('#imgList').append(newImg);
    });

There are a couple of problems with this. For one (which you should have already noticed if you’ve read the earlier part of this article), we’re making the $("#imgList") selection once for each iteration of our loop. The other problem here is that each time the loop iterates, it’s adding a new <li> to the DOM. Each of those insertions is going to be costly, and if our array is quite large then this could lead to a massive slowdown or even the dreaded ‘A script is causing this page to run slowly’ warning.

var arr = [reallyLongArrayOfImageURLs],
    tmp = ''; 
$.each(arr, function(count, item) {
    tmp += '<li><img src="'+item+'"></li>';
});
$('#imgList').append(tmp);

All we’ve done here is create a tmp variable that each <li> is added to as it’s created. Once our loop has finished iterating, that tmp variable will contain all of our list items in memory, and can be appended to our <ul> all in one go. Browsers work much faster when working with objects in memory rather than on screen, so this is a much faster, more CPU-cycle-friendly method of building a list.

Wrapping up

These are far from being the only ways to make your jQuery code run better, but they are among the simplest ones to implement. Though each individual change may only make a few milliseconds of difference, it doesn’t take long for those milliseconds to add up. Studies have shown that the human eye can discern delays of as few as 100ms, so simply making a few changes sprinkled throughout your code can very easily have a noticeable effect on how well your website or app performs. Do you have other jQuery optimization tips to share? Leave them in the comments and help make us all better.

Now go forth and make awesome!

Like what you read?

Comments

Comments are ordered by helpfulness, as indicated by you. Help us pick out the gems and discourage asshattery by voting on notable comments.

Got something to add? You can leave a comment below.

  • Alex Michael http://alexmic.net

    This is some good advice – I’d like to add my stone on the wall. On the last example, tmp += “…” creates an intermediary string on every iteration, resulting in poor performance when dealing with large arrays. You should instead make tmp an array, push the li’s in, and then join(’‘) it.

    Vote Helpful or Unhelpful

  • Jason Hummel http://www.wearechalk.com

    If you’d rather not play around with all that messy string concatenation when performing costly DOM manipulations, give createDocumentFragment a try.

    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)
    );

    Amazingly the browser support for documentFragments goes back to IE6.The benefit comes from the ability to add the entire fragment DOM tree into the page DOM with one insertion – just like the method outlined in the article.

    Vote Helpful or Unhelpful

  • Scott Kosman http://www.prayingmadness.com

    Bam! Here it is!

    http://www.learningjquery.com./2009/03/43439-reasons-to-use-append-correctly

    It’s a couple of years old but the idea is still solid. Pushing values into an array on each iteration and then using $(“whatever”).append(myreallylongarray.join(’‘)); to do your heavy lifting shows HUGE performance boosts. In retrospect this is the “right way” example I should have used for the DOM Manipulation section of my article, but hindsight is 20/20, etc.

    Vote Helpful or Unhelpful

  • Jeffrey Way http://net.tutsplus.com

    Nice article.

    …Just as long as people remember that, as long as you’re at least somewhat considerate of the selectors you pass to jQuery, you really don’t need to worry about selector performance too much. jQuery does an excellent job of optimizing as much as possible. But it’s good to understand the basic concepts, like right-left parsing.

    Sure – $(‘div’).find(‘p’) may potentially be fractionally faster than $(‘div p’), but I won’t lose sleep if I use the latter. Readability is more important in most cases….or unless there is noticeable slowdown in your page’s performance. :)

    Vote Helpful or Unhelpful

  • Joe Mottershaw http://www.hellowebdesign.co.uk

    This has been a very good read, it’s made me more aware of how sluggish my jQuery code actually is compared to how it could be!

    I have a question though, you mentioned caching, how does this fair with using $(this). For example, if you only called upon an element once in your script for a click detection, would you need to assign it to a variable first if that element was the same element also be altered? Some examples…

    1st Example

    $(”#div_id”).click(function() { $(this).hide(); });

    2nd Example

    var div_id = $(”#div_id”);
    div_id.click(function() { div_id.hide(); });

    Apologies for the bad example…
    But is there much of a difference in loading time between the two?

    Is $(this) a sort of variation of caching as it’s already selected the element and you’re just calling it back by saying “this one, the one you just found, yeah, use that”, or is it having to wade through all the code again to find it?

    Vote Helpful or Unhelpful

  • Rob L. http://rob.lifford.org/

    Useful tips all. One mini-pattern that I’ve picked up from co-workers is, when caching selectors, prefix your variable with $ to note that it’s a jQuery object. This can be really helpful in methods where you’re dealing with lots of variables, especially when you come back later to modify them or fix bugs.

    var $blocks = $(”#blocks”).find(“li”);

    Vote Helpful or Unhelpful

  • Agustín Amenabar http://medula.cl/

    Fantastic, specially liked the .find() optimization.
    For someone coming from ActionScript jQuery shares lots of optimizations.
    But DOM manipulation is the heavyweight here.

    I was expecting a mention to the second parameter of jQuery(), the context parameter. I was under the impression it narrowed the scope of the DOM search. Is it really faster? or is .find() better.

    I also have the doubt as to how does jQuery reads selectors. Is it like CSS (from right to left) or always goes for the ID first?

    Vote Helpful or Unhelpful

  • Aleš Roubí?ek http://rarous.net/

    Nice article.

    Last example can perform even better if you use array joining instead of string concatenation.

    var arr = [reallyLongArrayOfImageURLs], tmp = [];
    $.each(arr, function(count, item) { tmp.push(’<li><img src=”‘item’”></li>’);
    });
    $(’#imgList’).append(tmp.join(”“));

    Vote Helpful or Unhelpful

  • Alex Rohde http://alexrohde.com

    Interesting article, objective, useful, and well-supported. I really liked the part on event delegation.

    One thing I’m noticing is a schism in the developer community around conflicting sets of standards (performance, aesthetics, reusability).

    For example, though inserting inline HTML for DOM manipulaiton may be the fastest method, I recently was turned down an interview because a code sample did just this (which was a violation of separation of concerns or some such philosophical thing).

    Vote Helpful or Unhelpful

  • François Cassin

    Thanks for this great article !

    Here’s the test for the last part, ‘DOM Manipulation’, quickly thrown together, with a notSoLongImageArrayFromFlickr:

    http://jsperf.com/jquery-dom-manipulation

    Now, off to test it with a lot of different browsers :)

    Vote Helpful or Unhelpful

  • Scott Kosman http://www.prayingmadness.com

    Thanks for the feedback and questions, everyone. I’ll try to get to them all in time, today’s going to be a little crazy around the office, though, but I’ll do what I can.

    One quick response in regards to selector performance, right-to-left, context vs. .find(), etc.: this jsperf example runs through various methods and in almost all browsers (Opera being the lone exception), .find() outperforms other selectors.

    Caveat: all methods get obliterated by native JavaScript (see revision 69 of the same test for proof – I created rev 70 and removed the native version just to make the graph readable), but still.

    @Andi: yes, those two methods will generally yield pretty similar results. Using .find() for me is more force of habit than anything else.

    Vote Helpful or Unhelpful

  • JulienW

    here is the test for the first part :

    http://jsperf.com/find-vs-direct-selector

    Using find is actually faster, but not so much.

    Vote Helpful or Unhelpful

  • Matt Hinchliffe http://www.maketea.co.uk

    For further reading I would also recommend the following slides from jQuery core team member Addy Osmani and for some bed time reading: jQuery Fundamentals

    Vote Helpful or Unhelpful

  • JulienW

    As seen on this jsperf testcase : http://jsperf.com/various-jquery-testcases

    This is also way faster to use :

    $(document.getElementById(“foo”));

    than

    $(”#foo”);

    But really, is it really so important ? Most of the time, you just cache the result of the selector in a var once, and use it after this.

    Vote Helpful or Unhelpful

  • Scott Kosman http://www.prayingmadness.com

    I’ve gotten a few questions on the Twitters about multiple classnames, and how $(”.class”).find(”.other”) compares with $(”.class .other”). I’ve knocked together a really quick jsperf for that one, though I’ve only tested it in Safari/OS X so far. Hit it in different browsers and let’s see what’s the haps!

    http://jsperf.com/jquery-nested-class-selectors

    Vote Helpful or Unhelpful

  • RIchard Powell http://www.byrichardpowell.co.uk

    Really great article. The biggest surprise for me was that element selectors perform so well.

    Vote Helpful or Unhelpful

  • JulienW

    I also strongly disagree with the last part. Not about its speed but about its security. Really, doing string concatenation should light a warning in your head ! And I keep seeing these advice on every website talking about jQuery !

    Really, what is faster here is that you don’t access the node at each step of the loop. You can do this by adding elements to an “off-DOM” node. Yes, it will probably be slower than string concatenation, but still way faster than using an attached DOM node.

    So instead of using string concatenation, use jQuery’s “attr” function on a unattached DOM, and it should be nearly as fast.

    jsperf testcase to demonstrate this

    (feel free to fiddle with the testcase as it doesn’t seem so reliable on my firefox right now)

    Vote Helpful or Unhelpful

  • Rodney Rehm http://rodneyrehm.de/

    Kinda shocking how slow jQuery actually makes inserting nodes into the DOM

    jsperf.com/dom-insertion

    Vote Helpful or Unhelpful

  • Andreas Lagerkvist http://andreaslagerkvist.com

    Some nice tips here. I’m curious, what’s the difference between .on() and .live()? To me it seems they should both do the same thing so I don’t really get why .on() was added and what the potential differences between them are?

    Vote Helpful or Unhelpful

  • Scott Kosman http://www.prayingmadness.com

    @Andreas: with jQuery 1.7 the .live() method has officially been deprecated. The .live() API docs page lists a number of reasons why.

    Chiefly, it doesn’t perform as well as .on() (all events are attached to the document element), and doesn’t support chaining.

    Vote Helpful or Unhelpful

  • Nicolas Chevallier http://www.nicolas-chevallier.fr/

    Thanks for all these tips! They are not valid for JQuery moreover, it also works for Mootools for example.

    Vote Helpful or Unhelpful

  • Andi Farr http://semibad.com

    Julien: unless I’m reading it wrong, your test seems to show that appending to an off-DOM node is considerably slower than simply adding to the DOM directly in all browsers tested.

    You can make it slightly faster by adding the src attribute when you create the img element ($(’<img>’, { ‘src’ : item });) rather than using a seperate attr() call, but it’s still slower than just appending straight to the DOM – pretty surprising, not what I would have expected.

    Cheers!

    Vote Helpful or Unhelpful

  • Ben Plum

    Just to prove your first point on multiple element selector strings:

    http://jsperf.com/id-vs-class-vs-tag-selectors/12

    Vote Helpful or Unhelpful

  • JulienW

    @Andi: I’m quite surprised too. Especially on Chrome.

    It means that adding once as innerHTML is always faster than creating individual nodes.

    But I’m really not satisfied by this as it makes the code exposed to bad characters in strings (read: code injection).

    I’d like to see what happens with DOM document fragments…

    Anyway, I dislike to micro-optimize because the measured performance can change in the next browser version… I do prefer to code secure and reasonably fast, than the contrary. If jQuery is your bottleneck, you’re doing something wrong (like putting your model in the DOM).

    Vote Helpful or Unhelpful

  • Matthew

    Would it be possible for jQuery to detect when an ID is the first bit of a selector string and silently-internally do a getElementById call followed by a .find with the remaining string? I can’t think of any problems that would rise from this.

    Vote Helpful or Unhelpful

  • Michael Matyus http://maty.us

    I agree with ALEÅ  ROUBÍČEK, from what I’ve seen it’s better to use the .push/.join method than jQuery.each.

    Vote Helpful or Unhelpful

  • Mathias Bynens http://mathiasbynens.be/

    Nice write-up, Scott!

    Just a few clarifications:

    * `document.querySelectorAll(’:hidden’)` doesn’t actually work; in other words, supporting QSA doesn’t affect the performance of jQuery/Sizzle’s custom selectors. (The text makes it seem like it does.)
    * The reason Opera scores so well in QS/QSA tests is because it caches the results. It would be tricky but interesting to create a performance test case that works around this by avoiding repeated selectors.

    Vote Helpful or Unhelpful

  • Josh Hartman http://www.warpconduit.net

    Really nice article Scott, and thanks for the intro to the .on() method in jQuery 1.7.

    Vote Helpful or Unhelpful

  • dave mellett http://www.micelittlewebsite.co.uk

    Excellent article with some good tips. Be careful with caching when using ajax. New nodes added to the page will not exist in the cached selector, you’ll have to re-cache. Or even better, use .live() – or .on() in v1.7 I believe.

    Vote Helpful or Unhelpful

  • Scott Kosman http://www.prayingmadness.com

    Thanks for the clarifications, Mathias. :hidden was a bad example for me to use as the “title” for the pseudo-selectors section because as you correctly state, it doesn’t use qSA. Good call-out on that.

    I was totally unaware of Opera’s caching, too – I actually can’t run Opera on my work computer because it can be used to torrent so I can’t do a lot of testing with it!

    Vote Helpful or Unhelpful

  • Alan Moore http://www.alanmoore.info

    This article was a source of one excellent piece of information for me: that .live() had been replaced by on().

    I’m surprised that .live() hasn’t had more exposure with the rise of media queries and responsive design: if your page has an element hidden at its initial size (or added to the DOM when the size changes), then jQuery can’t attach, say, a ‘click’ to that element, since it’s not in the tree. Change your page width, add the element back in and… no jQuery action on click.

    Rather than $(‘a’).click(function() { … }); we use $(‘a’).live(‘click’, function(event) { … }); instead. It’s very powerful, but I was not aware that live() has been deprecated. Now I know better, and I will use
    $(‘a’).on(‘click’, function(event) { … }); instead!

    As for the performance issues, I must just not be doing enough with my scripts to tax the browsers. I develop in Safari, then Chrome, then Firefox. I test IE inside virtual machines with only 512Mb apiece and none of them have any performance problems. If I start to spot any, I’ll be back here to see what I can do…

    Vote Helpful or Unhelpful

  • Paul Irish http://paulirish.com

    @Matthew.. “Would it be possible for jQuery to detect when an ID is the first bit of a selector string and … do a getElementById call “

    It does that. :)

    https://github.com/jquery/jquery/blob/2a63b98/src/core.js#L141-143

    Vote Helpful or Unhelpful

  • Amber Weinberg http://www.amberweinberg.com

    Great article. I’m guilty of knowing jQuery and not Javascript myself (although I can’t stand either). I didn’t realize the find function was faster than a regular selector. :)

    Vote Helpful or Unhelpful

  • Bart Lewis http://www.bartlewis.me

    In regards to $(’.class .other’) versus $(’.class’).find(’.other’), the docs have this to say:

    Internally, selector context is implemented with the .find() method, so $(‘span’, this) is equivalent to $(this).find(‘span’).

    Vote Helpful or Unhelpful

  • pete weissbrod http://reallifedata.com

    I ran some of the js perf tests using internet explorer 9.0.8 and in quite a few instances I was surprised to see it outperform chrome. The new JS engine is extremely strict as I discovered when trying to use processing.js

    Vote Helpful or Unhelpful

  • Twest

    Nice article man, we may be reworking some of our app and the future way we do things because of this read and the new 1.7 on() support

    Vote Helpful or Unhelpful

  • daGrevis http://dagrevis.lv/

    One of the best articles I have read about jQuery so far. Pure awesomeness.

    I really would love to see next part of it. More tips – better internet! :D

    Vote Helpful or Unhelpful

  • Bertram Simon http://www.agentur-simon.de

    Great article. Thank you.

    little performance question:

    jquery 1.42 with ~ 70,4 kB and delegate

    or

    jquery 1.71 with ~ 91,6 kB and on

    What would you choose?

    Vote Helpful or Unhelpful

  • Scott Kosman http://www.prayingmadness.com

    Good question, Bertram. I’d (almost, see note below) always recommend using the latest version of the library. The addition of .on() is only one change of many since 1.4, there have been an absolute ton of additions and improvements over the last few releases.

    Besides, once the libraries are minified and gzip’d the file size difference will only be (by my best estimate) about 6 or 7 kb.

    The only time I’d be wary of going with the latest version is when updating the version of jQuery used in an existing project. Though updating is almost always painless, the chance of something breaking in your existing code when moving to a new version of jQuery is always present. When I’m using the Google Libraries API to load jQuery (which is almost every project) I will always specify the exact point version I’m loading rather than relying on it to just feed me the latest version. When a new version of the library gets rolled out I’ll switch to the updated version in a dev environment and make sure nothing’s broken before updating on live.

    Vote Helpful or Unhelpful

  • Aaron Peterson http://twitter.com/aaronlpeterson

    A great way to keep track of your cached jquery selectors (I think I picked this up from Alex Sexton) is to prefix the var names with a $. This makes it much easier to remember:

    var $elem = $(”#foo”).find(”.bar”);

    Vote Helpful or Unhelpful

  • Joe Larson http://joewlarson.com

    Great article and discussion. For my 2cents when I cache jquery objects I usually suffix with $ so I can remember that this is a jquery object (so “block$” instead of “block”). This is especially useful because I frequently grab the DOM node directly to work with it, so this avoids confusion about which thing I’m actually working on. I realize some people may dislike this for all the usual reason any Hungarian-ish notation is disliked, but in this case I find it very helpful.

    Vote Helpful or Unhelpful

  • monkey

    Speaking of speed, using jQuery.each to iterate over an array is bloody slow.

    Did one of these to test:

    http://jsperf.com/array-iteration-jquery-each-vs-for/2
    (also a lot of stuff to confirm my thoughts on where var’d stuff went)

    That also brought me to trying iterating over a jQuery collection in array style:

    http://jsperf.com/looping-through-jquery-objects/2

    I wonder how big an impact any of this speed stuff is going to make, though.

    Vote Helpful or Unhelpful

  • Adam

    “The IE JavaScript engine moves at the speed of an advancing glacier compared to more modern browsers, so optimizing our code for performance takes on an even higher level of urgency.”

    less than 9, yes I agree. But the engine in IE9, from what I’ve observed is better than any other browser, even those versions that have come along since IE9 was released.

    Vote Helpful or Unhelpful

  • Darren

    I guess I must be missed something? I always use CSS selectors like this:
    $(‘body > section div#content p’)…..
    which must let jQuery know not to bother looking anywhere else other than the top lever section element, etc? Surely the same – if not better – than the ‘find’ options being discussed???

    But great work!

    Vote Helpful or Unhelpful

  • Scott Kosman http://www.prayingmadness.com

    Good question, Darren. Logically you’d think that’s exactly how it works, but it’s actually the opposite. Sizzle (the CSS selector engine built into jQuery) parses selectors from right to left so in your case, it’ll search out all paragraphs, then determine which ones are inside div#content, and so forth.

    I knocked together a quick jsperf using your example and comparing it to a couple of different options using .find(), and .find() is significantly faster.

    http://jsperf.com/yet-another-jquery-selector-test

    Vote Helpful or Unhelpful

  • Katie Blackman http://elevatedthird.com

    This is a great guide for those who don’t get Javascript but understand enough jQuery to make things happen. It’s nice to finally get your jQuery commands working after reading and rereading the docs. But, as we do with our HTML and CSS, there is some clean-up always required. Performance is huge. Eight seconds is all it takes before someone’s clicking off your page onto something more interesting. This article is so helpful and will be tucked away in my bookmarks for when I need it next. Thanks!

    Vote Helpful or Unhelpful

  • Stephen Woodworth http://stephenwoodworthapps.com/MICS

    Thank you!!! This is gold, especially appreciate seperating religon from science with samples and data.

    Vote Helpful or Unhelpful

  • Spyros Rallis

    The best way to speed up jQuery is to not use it at all.

    Don’t use jQuery because you are afraid (or maybe bored?) to write some simple JavaScript. Don’t use a 30KB framework in place of 10 lines of JavaScript. <em>Think</em> before coding and don’t cut corners just to cut corners — a little bit more work may be a better solution.

    Now, don’t take me wrong — jQuery is a great framework and I love it. But I believe it is being overused.

    You wouldn’t need to optimize your jQuery code if you used the framework only where necessary, right?

    ;-)

    Vote Helpful or Unhelpful

  • Jose Galdamez http://www.josegaldamez.com

    I had no clue about the on() method in v1.7. After seeing it in use here it definitely makes more sense to attach event handlers to parent elements as you did in your table example.

    In your section on DOM manipulation, are you also implying that it’s faster to prepend/append strings as opposed to DOM nodes? I’ve heard the former is faster, but never actually done any speed tests myself.

    I noticed one small typo. document.getElementsByTagname should be document.getElementsByTagName (capitalize the “n” in “Name”).

    Excellent post!

    Vote Helpful or Unhelpful

  • Scott Kosman http://www.prayingmadness.com

    Hey Jose, sorry for the late reply.

    There are a ton of different methods for prepending/appending, and unfortunately the best answer to your question about performance is “it depends.” The point I was really trying to make was that, regardless of what kind of element you’re appending, it’s much more performant to append them all at once rather than appending one element in each iteration of the loop.

    I read a fantastic article about this recently that I’m trying to dig up again, it did a bunch of performance testing of various ways of appending using loops (both native for loops and jQuery $.each) and by far the best way was pushing content into an array in each iteration and then using that array to build the appended content after the loop was finished. If I can find it again I’ll post it here. Thanks for the question!

    Vote Helpful or Unhelpful

  • Phil Ricketts http://replete.nu

    I’m surprised nobody has mentioned jQuery’s selector context?

    $mysection = $(”#id”).find(“section”);
    jQuery(”[attribute=value]”, $mysection);

    Vote Helpful or Unhelpful

  • Scott Kosman http://www.prayingmadness.com

    Context was mentioned in the very first comment and I addressed it (along with a number of other things) in a jsperf a few comments later (here). Or is there something more specific you wanted to discuss regarding it?

    Vote Helpful or Unhelpful

  • Dodfr

    Very usefull tips !

    An other “pro” when you use the .on(‘click’,‘selector’,function({}) is that if you dynamically add a some element in ‘selector’ scope, then it will automatically be caught by the click event and you will not have to stick it to the event :-)

    Very usefull when you add new <li> items for example.

    Vote Helpful or Unhelpful

  • Andi Farr http://semibad.com

    Great article – I know I’ve been guilty of more than one of these before.

    Quick question on the first section – is $(”#id”).find(“p”) not equivalent to using the context attribute – $(“p”, “#id”)? They do the same, but I prefer the syntax of the second – no idea which is more performant, though!

    Vote Helpful or Unhelpful

Impress us

Be friendly / use Textile

About the author

Scott Kosman

A 35 year old Canadian expat currently plying his trade as Associate Director of Standards Architecture at Crispin Porter + Bogusky in Göteborg, Sweden, Scott Kosman can also be found on the Twitters and some of his other work can even be found on the internet. He likes JavaScript, bicycles, cats, bacon, and thinks you’re pretty awesome.

More information

Brought to you by:

Perch - a really little cms

The easiest way to publish fast, flexible HTML5 websites your clients will love.