How jQuery Beginners can Test and Improve their Code

How jQuery Beginners can Test and Improve their Code

Tutorial Details
  • Technology: jQuery
  • Difficulty: Beginner - Intermediate
  • Estimated Completion Time: 20 Minutes

jQuery’s arrival has made the process writing JavaScript laughably easy. But, you’ll notice that making small changes to your code improves the readability and/or performance significantly. Here are some tips to get you on your way to optimizing your code.


Setting up the Platform

We’ll need a solid platform to conduct our tests. Here is the HTML markup for the test page in which we’ll be running all our tests:

 
<!DOCTYPE html>
<html lang="en-GB">

<head>
<title>Testing out performance enhancements - Siddharth/NetTuts+</title>
</head>

<body>

<div id="container">
<div class="block">
<p id="first">
  Some text here
</p>
<ul id="someList">
  <li class="item"></li>
  <li class="item selected" id="mainItem">Oh, hello there!</li>
  <li class="item"></li>
  <li class="item"></li>
</ul>
</div>
</div>

<script  src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
  console.profile() ;
  
  // Our code here

  console.profileEnd();
</script>

</body>
</html>

There’s nothing special here; just a bunch of elements that we can target and test. We’re using Firebug to log the times here. profile begins the process, and profileEnd stops it, and makes a note of how much time the task took. I typically use Firebug’s main profile method, but for our devious purposes, this will be sufficient.


1. Detect if an Element Exists

As is often the case, you’ll be serving a single script file containing your code to all the pages in your site. This is usually code which often performs actions on nonexistent elements in the current page. Though jQuery handles problems such as these quite gracefully, this doesn’t mean that you can just ignore any problems. In fact, if you call jQuery’s methods on an empty collection, they won’t be run.

As a best practice, only run code which is applicable to the currently loaded page, instead of bunching all of your code into a single document ready check, and serving it to the client.

Let’s look at the first scenario:

console.profile();
var ele = $("#somethingThatisNotHere");
ele.text("Some text").slideUp(300).addClass("editing");
$("#mainItem");
console.profileEnd();
    
//Some more awesome, ground shattering code here ._.

Firebug’s spits out the following result:

Tutorial Image

This time, let’s check whether the element we’re looking to perform actions on exists before doing so.

console.profile() ;
var ele = $("#somethingThatisNotHere");
if ( ele[0] ) {
   ele.text("Some text").slideUp(300).addClass("editing"); 
}
$("#mainItem");
console.profileEnd();
    
//Some more awesome, ground shattering code here ._.

And the results:

Tutorial Image

See? It’s pretty simple, to the point and gets the job done. Note that you don’t need to check whether an element exists for every single bit of your code. You’ll notice in your page that certain bigger parts will generally benefit from this method. Use your judgment here.


2. Use Selectors Effectively

Try to use an ID instead of passing a class.

This is a big topic so I’ll keep it as concise as possible. First up, when passing in selectors, try to use an ID instead of passing a class. jQuery directly uses the native getElementById method to find an element by ID while in the case of a class it has to do some internal voodoo to acquire it, at least in older browsers.

We’ll look at the different selectors you can use to target the 2nd li element. We’ll test each one of them and how they modify the performance.

The first method, the easiest, will be to plainly target it using the selected class. Let’s see what Firebug’s profiler returns.

console.profile() ;
 
$(".selected");
 
console.profileEnd();
Tutorial Image

And the result: 0.308ms. Next, we prefix a tag name to narrow it down. This way, we can narrow down our search by first targeting only the selected DOM elements, with document.getElementsByTagName.

console.profile() ;
 
$("li.selected");
 
 console.profileEnd();
Tutorial Image

And the result: 0.291ms. Roughly 0.02 ms shaved off. This is negligible due to the fact that we’re testing in Firefox; however, it should be noted that this performance boost will be notably higher in older browsers, like Internet Explorer 6.

Next, we descend from the ID of the parent element.

console.profile() ;
 
$("#someList .selected");
 
console.profileEnd();
Tutorial Image

And the result: 0.283ms. Let’s try to be a bit more specific. We also specify the type of element in addition to the ancestor’s ID.

console.profile() ;
 
$("#someList li.selected");
 
console.profileEnd();
Tutorial Image

And the result: 0.275 ms. Another small part shaved off. Finally, let’s just target it directly using an ID to.

console.profile() ;
 
$("#mainItem");
 
console.profileEnd();
Tutorial Image

And the result: 0.165ms. Impressive! This really shows you how much faster it is to run native methods Note that while modern browsers can take advantage of things like getElementsByClassName, older browsers cannot – resulting in much slower performance. Always consider this when coding.


3. Account for Sizzle’s Parsing Model and Adding Scopes

Sizzle, the selector engine that jQuery uses – built by John Resig – parses selectors from right to left, which raises a few unexpected chains of parsing.

Consider this selector:

$("#someList .selected");

When Sizzle encounters such a selector, it first builds the DOM structure, using the selector as the root, discards items that don’t have the required class, and, for every element with the class, it checks whether its parent has an ID of someList.

To account for this, make sure that the right-most part of your selector is as specific as possible. For example, by specifying li.selected instead of .selected, you cut down the number of nodes it has to check. This is the reason why performance jumped in the previous section. By adding additional constraints, you effectively reduce the number of nodes it has to check.

To better fine-tune the way elements are obtained, you should look into adding a context for each request.

var someList = $('#someList')[0];
$(".selected", someList);

By adding a context, the way the element is searched changes completely. Now, the element providing the context – someList in our case – is first searched for, and once it has been obtained, child elements that don’t have the requisite class are removed.

Note that it’s generally a best practice to pass a DOM element as the context of your jQuery selector. Using a context is most helpful when it is stored in some variable. Otherwise, you can streamline the process and use find() — which jQuery, itself, does under the hood.

$('#someList').find('.selected');

I’d like to say the performance increase will be clearly defined, but I can’t. I’ve run tests on a number of browsers and whether the scoped approach performance beats that of the vanilla version depends on a number of factors including whether the browser supports specific methods.


4. Avoid Query Waste

When you’re browsing through someone else’s code, you’ll often find.

// Other code

$(element).doSomething();

// More code

$(element).doSomethingElse();

// Even more code

$(element).doMoreofSomethingElse();

Please don’t do this. Ever. The developer is instantiating this “element” over and over. This is wasteful.

Let’s see how much time such horrendous code takes to run.

 console.profile() ;
 
 $("#mainItem").hide();
 $("#mainItem").val("Hello");
 $("#mainItem").html("Oh, hey there!");
 $("#mainItem").show();
 
 console.profileEnd();
Tutorial Image

If the code is structured like above, one after the other, you can use chaining like so:

console.profile();
 
$("#mainItem").hide().val("Hello").html("Oh, hey there!").show();
 
console.profileEnd();

By chaining, the element initially passed in is acquired and a reference is passed along to each subsequent calls cutting down on execution time. Otherwise a new jQuery object is created each time.

But if unlike above, the sections referencing the element aren’t concurrent, you’ll have to cache the element and then do all the same operations as before.

console.profile() ;
 
var elem = $("#mainItem");

elem.hide();

//Some code
elem.val("Hello");

//More code
elem.html("Oh, hey there!");

//Even more code
elem.show();
 
console.profileEnd();
Tutorial Image

As is evident from the results, caching or chaining considerably decreases the execution time.


5. Perform DOM Manipulation more Intelligently

Suggesting non-traditional DOM manipulation in my earlier article drew a little flak from a few people before being shown that the performance boost really is worth it. We’ll now test it ourselves.

For the test, we’ll create 50 li elements, and append them to the current list, and determine how much time it takes.

We’ll review the normal, inefficient method first. We’re essentially appending the element to the list every time the loop runs.

console.profile() ;
 
var list = $("#someList");

for (var i=0; i<50; i++)
{
   list.append('<li>Item #' + i + '</li>');   
}

console.profileEnd();

Let’s see how it did, shall we?

Tutorial Image

Now, we’ll follow a slightly different path. We’ll essentially append the required HTML string to a variable firs, and then only reflow the DOM one time.

console.profile() ;
 
var list = $("#someList");
var items = "";

for (var i=0; i<50; i++){  
     items += '<li>Item #' + i + '</li>';  
 }
 
list.append(items);

console.profileEnd();
Tutorial Image

As expected, the time taken has decreased significantly.

Tutorial Image

If you’re using jQuery as a replacement for getElementById, but never utilize any of its provided methods, then you’re doing it wrong.

If you’d like to take things further, ask yourself if you really need to create a new jQuery object all for the purpose of targeting some element? If you’re using jQuery as a replacement for document.getElementById, but never utilize any of its provided methods, then you’re doing it wrong. In this case, we can get away with raw JS.

console.profile() ;
 
var list = document.getElementById('someList');
var items = '';

for (var i=0; i<50; i++){  
     items += '<li>Item #' + i + '</li>';  
 }
 
list.innerHTML = items;

console.profileEnd();

A Few Caveats

You’ll notice that the difference in execution time between the optimized and un optimized code is in the fraction of a millisecond range. This is because our test document is very small with an impossibly small number of nodes. Once you start working with production level sites with a few thousand nodes in it, it’ll really add up.

Also note that in most of these tests, I’m simply accessing the elements. When you start applying proper functions to them, the delta in the execution time will increase.

I also do understand that this isn’t the most scientific of methods to test performance, however, to gain a general feel for how much each of these changes affect the performance, I think this is suitably sufficient.

Finally, in most of your web apps, the connection speed and response time of the web server in question is going to play a bigger role in the performance of your app more than the tweaks in the code you’ll make. Nevertheless, this is still important information and will help you down the line when you’re trying to eke out as much performance as possible from your code.


That’s all Folks

And we’re done. A few points to keep in mind when you’re trying to optimize your code; this is not the all encompassing list of tweaks, of course, and the points may not necessarily apply to all situations. Either way, I’ll be watching the comments closely to read what you have to say on the topic. Any mistake you see here? Drop me a line below.

Questions? Nice things to say? Criticisms? Hit the comments section and leave me a comment. Happy coding!

Siddharth is Siddharth on Codecanyon
Tags: jQuery
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Robin

    Thanks for this – I’m pretty much a self-taught coder who has developed many of these bad habits – nice to see some more efficient ways to go about it.

  • A reader

    What? Sorry I cant heary you. My Developer tools, which are superior to Firebug and available by default in the superior browser , are begging me to be played with.

    http://up2go.us/static/img/naamloos1.PNG

    Lalalala

    • Om

      I am using Google Chrome Developer 6.0.466.0 dev, now, and am consistently Updating the Same. I am using Google Chrome From day 1 of its release, and love it, and preach it to others at such an extent that I have Convinced all my Colleagues to use it

      Its the Fastest Browser (specially JavaScript and HTML5) existing, “after Opera 10.6 (faster than it)”

      Chrome is super advanced, and so are the Developer tools in it, which WERE at one time better than Firebug < 1.5

      Today,
      Firebug is way way wayyyyyyyyyyyyyyyy more advanced than any other debugging tool provided by any Browser

      from Object Inspection, Dom Inspection, HTML Manipulation (faster than any Browser) to JSON parse, jQuery Object Support, and Bla Bla Bla …. It has every thing.

    • Om

      Check your word “Superior”

    • http://amberlightapps.com/widgetsbar Yarden Refaeli

      Do you know that they just copied it from the legendary Safari?

  • http://xpressabhi.com abhishek

    Hi,
    I am using firebug from a long time but I never used console feature.
    Thanks for this tutorial for jQuery.
    Thanks

    • http://davekingsnorth.com DaveKingsnorth

      I’m exactly the same, the console feature has passed me by for a while now.

    • jmarreros

      So am I

  • Nuruzzaman Sheikh

    Great article. very helpful
    thanx a lot for sharing. I never knew these useful firebug feature. I’ll use this right now.

  • http://www.deluxeblogtips.com Deluxe Blog Tips

    Nice tutorial. Not many developers understand the role of performance in web apps. These small tips are really helpful. Thanks for sharing.

  • http://www.wype.fr Wype web agency

    Nice tips, very useful! I never knew these firebug feature either, thanks for sharing!
    I recommand FireQuery to add another feature: with this add-on you can see all the events on your elements. Interesting for debugging and optimizing animations.

  • w1sh

    Nice tut and all, but can we go back to a few weeks ago when everything was in screencast format? I loved those times. I remember them like they were yesterday.

    • http://www.hambrook.co.nz Rick Hambrook

      I may be the minority but I prefer things in screenshot/code format like this rather than screencasts. Easier to move at your own pace (whether faster or slower than the screencast would easily allow).

      Also allows for quick skimming to more relevant parts too. Great tutorial, by the way. It’s very easy to slip into bad habits… especially for self-taught coders learning from varying sources.

  • http://www.alanagius.com Alan Agius

    Great article, Well surely help lots of us developers to write better code.

  • http://www.google.bg/search?hl=bgclient=firefox-ahs=SCcrls=org.mozilla%3Abg%3Aofficialchannel=sq=lamersmeta=aq=faqi=g9g-s1aql=oq=gs_rfai= LamerZ

    COde is boring for me.

    Just cant get it!!!

    i50; i++)

    what does it means?

  • LC

    Thanks for your article, it really helps. I find myself using many code snippets in one site and would like a similar explanation (as above) how to combine the (init) code lines into one file to avoid multiple http requests.

    Thanks!

  • http://www.designfollow.com designfollow

    great tutorial thank you very much

  • Lenin Yee

    Yes, this is helpful. Thanks!

  • http://bennthewolfe.blogspot.com Benn Wolfe

    Thank you, that was a very cool article with a lot of good tips. I will definitely be implementing these methods on my next project.

  • http://yeahnah.org Rowan

    Tricky stuff, thanks!

  • http://www.ryanjwood.com Ryan

    Thanks for the article! Pretty much all I have used the console for was logs, so naive!

  • Paperboy

    Thanks for the great jQuery tips!

    To check if an element exists I used something like this:

    if ($(‘#mySelector’).length) {
    //do tons of stuff
    }

    But does it work as good?

    • Abhijit

      You can use -
      if ($(‘#mySelector’)) {
      // do metric tonnes of stuff
      }

      • http://www.delucamarketing.ch NetHawk

        If you do that, and you’re manipulating #mySelector inside your condition, then you would violate rule #4.

        Checking with .length works perfectly but might be a litte bit slower than the method presented here. On the other hand it’s more readable…

      • http://www.hambrook.co.nz Rick Hambrook

        if (var el = $(‘#mySelector’)) {
        // do metric tonnes of stuff
        el.slideUp(); // etc
        }

        Not as readable, but workable. Not sure where it falls into with best practices though.

  • Sven

    thanks for sharing. very useful.

  • Meander365

    Great article with some great pointers.

    For those interested, more jQuery Performance Rules can be found over here:-

    http://www.artzstudio.com/2009/04/jquery-performance-rules/

    Cheers!

  • http://noteskeeper.ru/ mista_k

    BTW, rule “#someList .selected” will be processed in a special way: ID selector first, than CLASS selector. No need to do further optimization. In other cases, of course, search of elements will be start from the right most of selectors

  • http://www.hastishah.com Hastimal Shah

    Great article
    Nice tips for jquery performance improvement
    Please post more for performance improvement related to php,smarty and jquery.

  • http://www.xcellence-it.com/ Xcellence IT

    Hey, its really nice, just learned new technique to improve jquery performance…

    would like to read more on this…

    thanks for sharing

  • http://bluzgraphics.com Bluz

    Thanks Siddrah!
    This was very helpfull for me as I’v just started learnig jquery from the “Learning Jquery 1.3″ book. :)

  • http://webstandard.kulando.de/static/css-design CSS-Design-Blog

    Very nice debugging-tutorial based on firebug. Thx for sharing!

  • Bjorn

    Thanks for the great tips Siddharth. I’ll be sure to implement these in my upcoming project :-)

  • http://allenwei.cn allenwei

    “Perform DOM Manipulation more Intelligently” is very impressive, thanks Siddharth

  • http://www.slicemachine.com Zoran Jambor

    I’m guilty for quite a few of these points.
    Luckily, the more you learn, the less mistakes you make; and the code quality improves.

    Console.profile() is definitely must use (at least in bigger applications).

  • http://james.padolsey.com James Padolsey

    With #1, it would be better to “cache” the jQuery object and then check for existence of the elements — you’d get a much fairer profiling result this way (currently your creating two jQuery instances!!). Also, this is really a pointless optimisation in most cases as most jQuery methods don’t enact on an empty collection. Also, there are much better techniques to make sure that the code only runs when it needs to — checking for every single element is probably the worst way to do it.

    With #3, it’s important to note that Sizzle is only utilised in older browsers and when using jQuery’s psuedo-classes (filters like :input) — the right-to-left parsing is still used in most native implementations of querySelectorAll AFAIK. You mention that, with your first example (“#someList .selected”):

    “When Sizzle encounters such a selector, it first builds the entire DOM structure, discards items that don’t have the required class, and, for every element with the class, it checks whether its parent has an ID of someList.”

    This isn’t true. Sizzle (and I’d imagine most native implementations) optimise that particular selector so that #someList is used as the root of the search.

    Also, I think you mean “context” instead of “scope” — and you don’t need to do the whole $(‘#somelist’)[0] routine, just pass a string as the second arugment to $(…).

    “Note that it’s generally a best practice to pass a DOM element as the context of your jQuery selector.” — only if you need to set the .context property of the jQuery instance (useful for things like the live() method)

    In reference to #4 — “$(element).doSomething();” — doesn’t query the DOM whatsoever, it simply creates a new jQuery instance, and yes, this is wasteful and a good reason to utilise chaining, or to simply assign your jQuery object to a variable to be used later. But, chaining shouldn’t be used for performance’s sake; it should be used when it makes sense.

    Your third piece of code in #5 should NEVER be used in practice. Copying the innerHTML and then filling-it-up and then re-inserting it into the DOM will immediately get rid of any event handlers, and data bound, and any states preserved within the DOM elements. Don’t do this. And I don’t kow what the last chunk is about, when you’re not even using jQuery… Plus, these are unrealistic examples — why would one want a list of numbers? – it’s more typical to fill a list with text from an array, in which case you can use array.join()…

    It makes no sense to me that you are paid to spread this kind of misinformation. I’m not having a go at you, but seriously, you need to learn more about jQuery and JavaScript. Please.

    • http://www.ssiddharth.com Siddharth
      Author

      First off, thank you for your input.

      And before we start, I’d like to say this. I’m not advocating that people should do anything here, in *everything* they do. This is more along the lines of me saying “Hey, I put together these small test cases and these small things net some decent performance gains. You could maybe look into these in the future.” As in painfully apparent, doing any of these without considering the context is dangerous.

      About #5, I’m not advocating doing this for every instance where the DOM elements and/or the data it contains changes. As you so eloquently put, doing such a thing will get rid of the handlers attached to it leading to unnecessary problems. But there are certain cases when this technique becomes useful. Imagine you’re pulling a few hundred records and replacing the current data with the updated data. I think you’d be better off just replacing the content instead of appending the updated data and then removing the old data. As I’m saying repeatedly, use your judgment to decide whether the change makes sense in that context.

      About #4, yes, chaining should be done when it makes sense but I frequently see people obtaining the same element in contiguous lines when they could have just chained. I figured in these cases, chaining not only makes sense but also gives a performance increase to boot.

      About #3, yes I meant context, not scope. My bad. And I thought the right to left model applied uniformly to all browsers. I stand corrected. And humbled.

      About #1, I’m sorry but I don’t see where I ask people to check for the existence of every element. I’m merely saying that if people have a particular, power hungry block of code, it’d be better if they actually check if the element exists in the page before doing so. I’m not asking anyone to check the element’s existence all the time. I’m aware there are other methods but this happens to be the simplest of the solutions and coyly ties into the beginner part of the title.

      Thanks for reading. :)

      • http://james.padolsey.com James Padolsey

        Please see my reply in the next thread.

      • http://www.jeffrey-way.com Jeffrey Way

        Hey guys. I’ve made a couple modifications to his tut to reflect the excellent comments. I’ll make some more over the course of the day.

  • Carlos

    YEAH BABY!

  • zxh

    for string concatenate manipulation , we can use array’s push method instead of “+” operation , like this: var names = [];
    for(var ii=0 ; i< 1000; i++)
    {
    names.push("name"+i);
    }
    var result = names.join("");
    names = null;

  • http://halhelms.com Hal Helms

    @James,

    I’m sure the author was giving the best advice he knew. And, as you point out, his advice (and his knowledge) isn’t always good. Having read your blog regularly, I know that you have a very deep knowledge of jQuery and JavaScript. The question is how do we get people like you properly paid enough to invest the time to provide really deep, rich sources of information? Writing a book won’t do it: there’s not enough money in it.

    This is a big problem. Developers google some search terms to hopefully find an answer to their question. They’ll find something, sure, but is it any good? Too often, they have the same “success” that Jenny McCarthy did when she went to “the University of Google” (her phrase) to “discover” the link between autism and childhood immunization. The fact that no link exists didn’t stop her — and the countless numbers of parents she’s influenced — from believing that it does. It’s another case of bad information.

    Until we find an answer to the general problem, thanks for setting the record straight on this one, small instance of not-so-good information.

    • http://www.ssiddharth.com Siddharth
      Author

      Please refer to my reply above. Thank you for reading.

    • http://james.padolsey.com James Padolsey

      First, “innerHTML” isn’t always faster, especially for decent browsers that optimise for proper DOM methods: http://jsfiddle.net/kCU63/

      Secondly, this article is targeted at beginners. I have doubts whether someone classed as a “jQuery beginner” should even be thinking about profiling their code. At that stage it’s important to learn the API, and that’s all! Best practices should definitely be instilled but perhaps at a later stage, and should be done so generically. jQuery is JavaScript. JavaScript best practices apply to jQuery. There’s no advantage in throwing around jQuery optimisations, especially when you use questionable terminology.

      When you say “The developer has essentially obtained the element in question again and again instead of reusing a reference to it.”… You really mean, instantiating jQuery objects can be expensive so it’s important to limit it, whether that be by chaining method calls or by assigning objects to variables and referencing them in your code.

      Concerning #1, I understand that you might not have been condoning that such a technique be used exhaustively, but it came across that way. This is an article on how jQuery beginners can improve their code, and your number one tip (it seems) is to check for element existence… this is one of the things jQuery’s API protects against — methods can be called on an empty collection (this is strength of jQuery). Your reasoning is fair: there’s no point in doing a great deal if the element isn’t even present; but this isn’t relevant to a beginner. Fooling beginners into thinking that these types of minor optimisations matter is probably not a good idea. Sure, they do matter on a massive scale, when constructing multi-view RIAs, but most developers/designers picking up jQuery are doing so to add effects and enhancements to their brochure websites, not to construct the next gMail.

      Your points aren’t all invalid. Many of them fall in-line with well-known JS best practices, but I really don’t think showing screenshots of a single environment’s profiling results serves as a decent way of illustrating your points. Your tutorial could be condensed into four or five bullet points… and readers would have a far easier time reading that than a stretched-out article with lines of opinion, rhetoric and some slight fabrications.

      The only tip I wish to convey to beginners is the following: Learn JavaScript, get awesome at it, and then learn jQuery (or your library of choice).

      • http://james.padolsey.com James Padolsey

        Whoops. Added the comment to the wrong thread…

      • http://www.ssiddharth.com Siddharth
        Author

        “You really mean, instantiating jQuery objects can be expensive… ”

        Yes, I meant instantiating a jQuery object when I meant obtaining the item. I meant to twist the naming/terminology a little so a beginner may understand it a little better. For someone who wants to cater to beginner and intermediates, I don’t want their eyes to glaze over. In retrospect, it seems taking my time and just explaining the concept in question may have been the better way.

        For the reader, here is one of James’ articles explaining what it means. Look through the first point: http://net.tutsplus.com/tutorials/javascript-ajax/uncovering-jquerys-hidden-features/

        “Your reasoning is fair: there’s no point in doing a great deal if the element isn’t even present; but this isn’t relevant to a beginner.”

        Surely, you want these beginners to move up the ladder, eventually. Either way, it’s just a point I wanted the reader to know that such a technique exists. I don’t think there is any harm in that.

        “The only tip I wish to convey to beginners is the following: Learn JavaScript, get awesome at it, and then learn jQuery (or your library of choice).”

        Amen to that.

      • Abhijit

        “The only tip I wish to convey to beginners is the following: Learn JavaScript, get awesome at it, and then learn jQuery (or your library of choice)”

        That’s simply great. Like it!

  • http://www.jordanwalker.net Jordan Walker

    Great write up, very solid tips!

  • http://unscriptable.com/ unscriptable

    It seems that this post started out with good intentions: How to show junior javascript programmers how to use the Firebug profiling commands. However, due to crappy jQuery advice, turned into an illustration of web programming anti-patterns (aka “Programming No-nos”).

    I have to agree with James (of course), and would add the following:

    ———-

    Premature optimization.

    Do not try to second-guess the framework (jQuery, prototype, dojo, etc.) unless you’ve already got a performance problem. The people who build those frameworks have done an excellent job and have designed them to work well in most situations.

    ———-

    “Try to use an ID instead of passing a class.”

    Do NOT use IDs! Use classes! Modern browsers optimize quite well when using classes. There might be a slight performance decline when using classes, but it’s worth it. Even on old browsers that don’t optimize class lookups, it’s still important to use them. Here’s why/how:

    Any non-trivial web page can be split into functional areas / modules. Let’s take a chat application that allows multiple chats arranged in tabs. Each tab has a chat stream (with several chat messages in it each with bits of info about author, time stamp, text message, etc), a textarea for text entry, an emoticon selector, and a Send button.

    Now let’s say you take Siddharth’s advice and use IDs on all of those elements (let’s focus on the chat stream, textArea, and/or Send button). Well, the first problem is that you need to make each ID unique. “Hm. Ok, we’ll just add a number at the end of each like this: sendButton_1, sendButton_2, sendButton_3…”

    So now your server code (or templating engine) just got more complex. It needs to generate unique IDs. Your javascript just got more complex, too. It needs to also generate IDs and IT MUST GENERATE THEM USING THE SAME EXACT ALGORITHM AS THE SERVER.

    I’ve seen people do this for several levels of modules. For example, if you wished to place a Like button on each chat message, it might look like this: Like

    Not only is this ugly, but it also complicates the code, makes it slower (generating unique IDs), and — most importantly — creates an implicit (and likely undocumented) dependency between the server code and client code. This makes it harder to maintain.

    [I deleted a long example of how to use the context parameter of the jQuery selector, but decided it was way off topic and probably not fit for the intended audience. :( ]

    In short, use the context parameter (the second one in the jQuery function): jQuery( selector, [ context ] )

    Example:
    $(‘.someClass’, contextNode)

    You should almost always have this context available. Use it.

    ———-

    “If you’re using jQuery as a replacement for getElementById, but never utilize any of its provided methods, then you’re doing it wrong.”

    No. You are doing it wrong, Siddharth. The reason the industry has embraced these frameworks is to ride on the shoulders of giants. What if the geniuses behind jQuery (or dojo or prototype or mootools…) figure out a way to lookup elements even faster than document.getElementById? Or what if a new W3C-approved browser API is added that works better? Furthermore, what if a new feature request is added to the project that requires more than just looking up the element by ID (e.g. add a class or attr to the node)???

    Again, premature optimization ruins some perfectly good code. If you are a junior web developer, choose a framework and just use it until/unless there is a performance problem. (Developers should obviously learn techniques to avoid performance pitfalls as you show in the first half of #5.)

    ———-

    OK. Calming down now….

    It’s good to illustrate the tools we have in Firebug. I applaud you for that, but please, please, PLEASE don’t preach bad practices to junior developers or you’ll just get flamed by James (and myself). ;)

    – John

    • http://www.jeffrey-way.com Jeffrey Way

      Hey John –

      Good comments. In reference to the use of getElementById, that’s actually one of the couple notes that I added myself. I’ve found that a bunch of sites only use a very minimal use of jQuery — and truthfully don’t even need it.

      In those cases, why added the extra overhead, if you can use regular JavaScript?

      I totally get your point that the file size of jQuery is extremely low to begin with, and that it’s generally best to assume that they’ve accounted for these possibilities — but I’m not so sure that I agree with blatantly using jQuery without a second thought.

      But other than that, thanks for chiming in!

      • http://www.jeffrey-way.com Jeffrey Way

        P.S. You’re always free to write a tutorial for us. :) I’ve been wanting to commission a jQuery article, called “What you’re doing Wrong in jQuery.” Interested? Or James?

      • http://www.ssiddharth.com Siddharth
        Author

        Let me see.

        I have not advocated and am not advocating premature optimization. As I’m repeating, time and again, in the article and in the comments: *use your judgment*. As I say again before the conclusion, chances are you’ll never have to optimize so.

        Secondly, in most the browsers I’ve tested, looking up a node by ID still is a *lot* faster than looking it up using its class. And regarding your test case, I imagine I have to say this once more: no point in implementing this everywhere. In your case, it’s painfully apparent assigning unique IDs and then working on it is a pain. In these cases, going with classes is the obvious choice. I’m not sure why people are saying I’m arguing against this. I’m not.

        Regarding the final concern you voiced, I think Jeffrey has it covered. No point in including a 155kB file to use as a wrapper for getElementById.

        The points you make may be technically sound but sugar-coated smiley-interlaced prose such as these doesn’t negate nor mask the obvious spite with which you write.

        Thank you for reading and definitely for the input.

    • http://www.ssiddharth.com Siddharth
      Author

      Wrong thread. Ugh. See my reply to Jeffrey’s reply. :)

    • Abhijit

      “Do NOT use IDs! Use classes!” – what do you mean by this? Can you elaborate? Is it wrong to use IDs where they can be? By the way, the example you have given about the chat application, using classes is obvious in that, is it not?

    • Om

      Ughh…

      What a funny example of a Chat System. ha ha… Whats ur age unscriptable?

      I think u should definitely look into ur coding basket, before calling the above tips as premature optimisation

      To James Padolsey:

      I think both of u (u and unscriptable) have not worked into Production Environment, and are amateur developers, of a small firm, with free internet access to staffs.

      How many RIAs have u built lately James.

      We are actually Building a next Gmail, (similar app for our company employees, with a little Google Wave like functionality) a very High End App. and We are using ExtJS and jQuery both

      You know what are live sites?????

      I will tell you, the sites that are on mmmm…. ok, on ‘Web’, which u access by http protocol, prefixing http://www...

      It has Millions and millions of records, & to serve the files is really a great issue

      1st page should load in not more than 2 sec, second in not more than 1

      I think both of u belong to that category of Coders, who result into sites that Hang the system once opened or hog memory…(I wonder y when I open some tabs in FireFox, the task manager shows lot of memory consumption)

      Have u seen Google’s implementation of jQuery, BBC’s glow, Google’s own Javascript
      They have optimized heir code for SPEED
      Go check the jQuery Core, and u will find the same

      how can there b a faster implementation of get element by id, than native, unless there was a new language, or caching techniques, or new upcoming Google Protocol SPDY (not HTTP) implementing native standards

      it is clear in eg. 5 that u are not attaching event handlers to ‘li’ elements, why the hell would u append such elements in a for loop

      How many Chat systems have you built unscriptable, check Gmail’s inbuilt chat system, it work on IDs
      if u change theme, classes change, but the IDs do not

      dont forget that jQuery is a ‘Write Less Do More query’
      I think u dont have the basic idea of why these JS Frame works have been made
      They r made for simplicity and speed, ease of achievements, cross browser compatibility and not for using inbuilt optimization of modern browsers

      $(‘A’, ‘B’), if u know the sizzle engine, – queries the DOM for ‘B’ – find ‘A’ in ‘B’ – returns Object ‘A’

      Do you know ‘How the DOM is structured’

      ‘selecting Elements by Class is slowest of all and should be avoided wherever possible’ – John Resig

      ID is the identity of the element, it has more preference than the tagname itself

      ‘#id’ is faster than ‘div#id’,

      whereas ‘div.classname’ is faster than ‘.classname’
      Class is for grouping elements, mainly for styling, etc. something common. Like the posts here must be having same class

      The tip no. 5 is a tip given by John Resig, himself, if at all u check his blog. – optimiziation using DOM Fragments:
      http://ejohn.org/blog/dom-documentfragments/

      Seeing the comments of Siddharth, I feel that he should not give important to such time wasting and more confusing/demotivational comments, not actually intended to the audience and oriented towards debate or proving I-am-jQuery-Coder type mentality

      James and unscriptable must be working in small firms, with free internet access to staffs, with little or no experiences in Production/Enterprise level coding

      Good tutorial though, except where u have said about $(‘parent child’) selectors
      acc to u it searches the children and then checks whether their parent is ‘parent’

      which is not true.

      $(‘parent child’) searches for ‘parent’ first and then all children descendant to it, returns them

      whereas

      $(‘parent > child’) will return only direct descendants only

  • Carlos

    YEAH BABY!! (with Australian accent!!)

  • http://www.goblinridge.co.uk Ted Thompson

    Great article. Learnt a lot. Cheers Ted

  • olivvv

    yes example 1 is just too confusing to noobs imo. Kinda do thism but dont do it. In the end the snippet provided should not be imitated – 2 queries is wrong – a cache should be used.

    • http://www.ssiddharth.com Siddharth
      Author

      As I’m constantly saying, choose where to use this wisely. I’m not advocating using it everywhere. Use your judgment.

      Thanks for reading.

  • Raj

    Nice tutorial, quite informative. Thanks.

    @James: While I understand you possess more knowledge about this subject than the author, that’s hardly an excuse to be utterly condescending and disregard his efforts. Unintentionally or otherwise. And quite frankly, if you’re bothered by his articles this much, why not just write some tutorials yourself and show everyone how its done? By your comments, you’ve proven yourself to be more than capable. However, till you do that, please put the tissue down and stop being such a crybaby.

    • http://james.padolsey.com James Padolsey

      I’ve kept my comments about the issues, why don’t you? Ad hominem won’t get you anywhere. I do write articles and tutorials about these topics,.. so what more do you want? Are my intentions skewed? I want to make sure beginners are being given the correct information. Is this such a pointless pursuit?

    • http://www.delucamarketing.ch NetHawk

      Sorry, but such comments will discourage people to offer their opinions and knowledge. I think James made clear, that this is about the issue and his points are – as you admit – good ones. And if you do some googleing, you’ll see, that James is publishing tutorials AND even finds the time to read others and contribute to them as well.

  • mesr

    This is good to know

  • http://www.BertrandLirette.com Bertrand

    Thanks for the tips. I’ve never felt the need to optimize every ms of my code since I’ve never build huge web apps. Is it really important to optimize and save 10ms overall? It’s not like it was like 10% of the time it took to rendre the page…is it?

    And about those ms, that means the “client” will spit the code faster if you optimize it, right? It seems like a lot of time to optimize the code just to save 10ms if I can cut 10k off an image on my site in matter of seconds…?

    Thanks for clearing this up.

    PS: Typo in the end : “Ffinally, in most of your web apps”

    • http://testing.misconfused.org Nick Tulett

      It’s not just 10ms , it’s 10 ms
      every time that code is hit,
      every time through the loop,
      potentially every click,
      mouse move or
      window resize.

      For every visitor.

      On every visit.

      That adds up to hours and hours of wasted time and energy you can never repay.
      Is that not worth a few minutes of your own time?

  • Mike

    #5 > second-to-last snippet:

    console.profile() ;

    var list = $("#someList");
    var items = list.html();

    for (var i=0; i<50; i++){
    items += 'Item #' + i + '';
    }

    list.html(items);

    console.profileEnd();

    You can shave more time by not referencing your cached ‘list’ to create the ‘item’ var. Especially when you plan on overwriting it.

    console.profile() ;

    var list = $("#someList");
    var items = '';

    for (var i=0; i<50; i++){
    items += 'Item #' + i + '';
    }

    list.html(items);

    console.profileEnd();

    This took the profile times down from (3.437ms, 5 calls) to (2.963ms, 4 calls).

    The same applies to the ‘list’. If you aren’t going to use the ‘list’ more than once, there’s no need to cache it.

    console.profile() ;

    var items = '';

    for (var i=0; i<50; i++){
    items += 'Item #' + i + '';
    }

    $("#someList").html(items);

    console.profileEnd();

    This took the profile time down to (2.650ms, 4 calls).

    There’s a lot of poorly written code out there and even more bad information about optimization. Thanks for fightin’ the good fight.

  • http://twitter.com/maxberndt Max

    thanks for this great article, Siddharth! First time for I while I read from beginning to end. And now, off I go to James giant comment to read it.

  • http://twitter.com/aforavi Avinash

    Good Article !!
    Thanks for valuable tips.

    Best Regards
    ~Avinash

  • julie

    As a jQuery beginner trying to become intermediate this article and the discussion has been very useful. Thanks for writing the article Siddharth and thanks to all the experienced developers giving advice. Please be kind to each other. I think everyone has the right intentions.

    I have a question about the best way to incorporate plugins. Since the point was made that hits to the server are bad–and I did know this already–what is the best way to use and manage my plugins? I often use colorbox and validate for example and link to them separately. Sometimes I have a link to jQuery and then 4 other linked scripts. How does this rate in terms of efficiency and what should I do about it? Should I bundle them into one file and link to that?

    Also, it’s often the case that we (CSS/designers) don’t have full control over the way a CMS outputs each part of the code. In some cases I can simply link to external JS files (one containing all of my custom scripts for a given site) and so I can’t ensure that the code won’t target non-existent elements on some pages. How big a deal is this?

    Thanks in advance for your help!

  • Rowan

    You left out the time comparison in the last two graphics, why is that? Why are you leaving those numbers out? I bet they’re exactly or closely the same despite the number of calls.

    In regards to your comment “this has saved 0.1 of a ms, which isn’t much, but it’s important is slower browsers like IE6″ I don’t think is the right thing to say.

    Each browser often has their own implementation of JavaScript, where the performance profiles are _completely different_. You cannot compare performance improvements in Firefox to that in IE* or Chrome for that matter.

    Also, there are 1000 milliseconds in 1 second. You are saving 0.1 of a millisecond, that is 0.1 of 1 of the 1000 milliseconds in 1 second. It is hardly negligible.

    I think this article would have been better served written in such a way to teach how to look into your code to see what it’s doing to spot performance problems, not give specific (poor) advice on ‘how to do things right in jquery and javascript’.

    Better luck next time. Beware giving advice. Teach people how not what. That is all.

    • http://www.ssiddharth.com Siddharth
      Author

      “Also, there are 1000 milliseconds in 1 second. You are saving 0.1 of a millisecond, that is 0.1 of 1 of the 1000 milliseconds in 1 second. It is hardly negligible.”

      There is also the fact that the test document only contains very few nodes. Ramp it up to a production level document and you’ll see the gains. Which is exactly what I said in the article.

      Thanks for reading.

  • http://www.oryzone.com loige

    Wonderful article :)
    Performance always matters, also on client scripts!

    tnx for sharing

  • http://www.delucamarketing.ch NetHawk

    We should acknowledge, that writing this article which brings up good points, triggered very valuable information by James – the JS Giant – Padolsey. Now, I would have missed James’ thoughts on this without the article. And I think we should see articles as starting points, where the cloud intelligence can contribute and make the content more valuable and more complete.

    Thank you both (and all the others, contributing to this and other articles and tutorials).

  • http://www.jamesduncombe.com James Duncombe

    Great tutorial. I’ve been using jQuery for a little while but I’ve never used the console with Firebug before. It’s going to really help. Thanks again,

    James

  • Eddy Proca

    That’s a poor choice of title, talking about the target of this article in third person. It detaches both the author and the audience from the “beginners”.

  • http://www.yunusemreunal.com oyun haberleri

    good article. thanks for sharing.

  • moxx

    There are some fails because you cant use profile for time values of native js code.
    The console.profile just mesure the time of an function between the profile start and End section.

    console.profile(‘MyTime’);
    $(document).find(‘div’).each(function(){
    $(this).css(‘color’ : ‘red’);
    });
    console.profileEnd(‘MyTime’)

    //become an -> MyTime (2.388ms, 224 Aufrufe)

    console.profile(‘MyTime’);
    $this = document.getElementsByTagName(‘div’);
    for(i=0; i There is no activity that could be measured.

    //lets try in a function
    function nativejs(){
    $this = document.getElementsByTagName(‘div’);
    for(i=0; i MyTime (1.627ms, 1 Aufruf)

    So if you mixed JQuery functions with nativ js code you become always faster because the native js isn’t mesured in the profiler time.

  • http://www.brettwidmann.com Brett Widmann

    This has been a really helpful tutorial. Thanks for sharing.