views:

1264

answers:

4

I am writing a jQuery plugin and I am at the optimization stage.

I wonder which of these leads to a quicker script in general, and what sort of mitigating factors are important:

  1. Have the script generate lots of classes and ids at the start so finding elements in the dom is easier (quicker too?) later on.
  2. Keep classes and ids to a minimum (so save time by not creating them), but then look for elements in more convoluted ways later (eg the nth item in an object), which I presume is slower than getting by id/class.
+4  A: 

I think you answered your own question: 'convoluted ways' is a synonym for 'it will break' - any changes to the html structure will break your code.

For example, imagine you're trying to get myDiv and you assume it's the last sibling of child:

<div>parent
     <div>child</div>
     <div>myDiv</div>
</div>

What happens if you later decide the structure should really be like this?

<div>parent
     <div>child</div>
     <div>myDiv</div>
     <div>child</div>
</div>

By relying on assumptions about structure your code becomes really brittle. Adding classes and ids to nodes will prevent such scenarios.

I think you should go with the first choice. Do also remember that getting nodes by class is always slower than getting them by id.

Gabriel Florit
Great point, convoluted = brittle
Juan Mendes
+2  A: 

With my plugins I try, as best I can, to limit the amount of hooks I introduce into the document. By "hooks" I mean IDs or classes.

The best way to avoid them completely is to retain references to any created elements within your plugin's closure. For example:

jQuery.fn.addList = function(items, fn){
    var $list = $('<ul/>').html('<li>' + items.join('</li><li>') + '</li>');
    return this.each(function(){
        $(this).append($list);
        fn.call($list);
    });
};

$('body').addList(['item 1', 'item 2'], function(){
    var referenceToTheList = this;
    console.log(referenceToTheList, '<- this is my list, no hooks involved!');
});

The list can be carried around JavaScript functions (referenced and used in multiple places) without requiring any hooks in the HTML; thus making it as unobtrusive as possible!

Avoiding/limiting hooks is especially important in plugin development because you never know where it might end up being used.

J-P
+6  A: 

The question is not really specific enough so I can give you advice directly relevant to your code, but here are some of my favorite jQuery optimization tips:

  1. Whenever possible, specify a context! Don't make jQuery look places it doesn't have to. If you know that something is going to be inside the #container div, then do $(something, '#container');
  2. .myclass is slow. Internally, jQuery has to go through every single element to see if it has the class you are searching for, at least for those browsers not supporting getElementsByClassName. If you know that a class will only be applied to a certain element, it is way faster to do tag.myclass, as jQuery can then use the native getElementsByTagName and only search through those.
  3. Don't do complicated selectors in one bang. Sure, jQuery can figure out what you want, but it takes time to parse out the string and apply the logic you want to it. As such, I always like to separate my "queries" out into patches. While most people might do $('#myform input:eq(2)'); or something like that, I prefer to do $('input','#myform').eq(2); to help jQuery out.
  4. Don't re-query the DOM if you plan on doing multiple things with a set of objects. Take advantange of chaining, and if not possible to use chaining for whatever reason, cache the results of the query into a variable and perform your calls on that.
Paolo Bergantino
Great tips - will come in handy right away
wheresrhys
+6  A: 

The way the browser works is that upon load it creates an in-memory DOM tree which looks as follows:

                                              P
                               _______________|______________
                              |                              |
                          childNodes                    attributes
                ______________|___________                   |
               |              |           |            title = 'Test paragraph'
         'Sample of text '   DIV   'in your document'
                              |
                          childNodes
                    __________|_______
                   |          |       |
           'HTML you might'   B     'have'

So when you lookup P > DIV > B, the lookup has to find all P elements, then find all DIV elements within P and then find all B elements within DIV. The deeper the nesting the more lookups it needs to do. Further, it might find all P > DIV only to find that none of them have B and it will have wasted time looking through all P > DIV matches.

Lookups by ID are faster because IDs are guaranteed to be unique so the DOM can store them as hash tables which has very fast lookups. In terms of jQuery the implementation might be slightly different, however, document.getElementById has the fastest lookup time so $('#my_node_id') should also be quite fast.

Consequently, if your node doesn't have an ID, you can find the nearest ancestor that does and find the node relative to that ancestor

#my_node_id > div > b

because the look up only needs to happen under the sub-tree of #my_node_id it will be faster than p > div > b

aleemb
+1 for the kick ass ASCII graph alone.
Paolo Bergantino
+1 for lookup by ID.
Soviut