$30 off During Our Annual Pro Sale. View Details »

jQuery Performance Tips & Tricks

Addy Osmani
October 29, 2011

jQuery Performance Tips & Tricks

A talk outlining several jQuery performance tips, tricks and best practices that are useful to keep in mind when developing using the library.

Addy Osmani

October 29, 2011
Tweet

More Decks by Addy Osmani

Other Decks in Technology

Transcript

  1. jQuery Performance
    Tips & Tricks
    Addy Osmani, Jan 2011

    View Slide

  2. About Me
    Senior Web Developer (currently a PM)
    jQuery Bug Triage, API Docs and Blogging
    teams
    Write for .NET magazine, my site and a few
    other places.

    View Slide

  3. I <3 jQuery

    View Slide

  4. Why Performance?
    Best practices are very important
    Don’t follow them and browsers end up
    having to do more work
    More work = more memory usage = slower
    apps..and you don’t want that.

    View Slide

  5. Tip 1: Stay up to date!
    ALWAYS use the latest version of jQuery core
    Performance improvements and bug fixes are
    usually made between each version
    Older versions (eg. 1.4.2) won’t offer these
    instant benefits

    View Slide

  6. Tip 2: Know Your
    Selectors
    All selectors are NOT created equally
    Fastest to slowest selectors are:
    ◦ The  ID  Selectors  (“#AnElementWithID”)
    ◦ Element  selectors  (“form”,  “input”,  etc.)
    ◦ Class  selectors  (“.someClass”)
    ◦ Pseudo  &  Attribute  selectors  (“:visible,  :hidden,  
    [attribute=value]  etc.”)
    ID and element are fastest as backed by native
    DOM operations.

    View Slide

  7. Pseudo-selectors: powerful but slow
    :hidden (above) is powerful but must be run against all the elements in
    your search space
    Pseudo/Attrib selectors have no browser-based call to take advantage
    of
    if  (  jQuery.expr  &&  jQuery.expr.filters  )  {
      jQuery.expr.filters.hidden  =  function(  elem  )  {
        var  width  =  elem.offsetWidth,
          height  =  elem.offsetHeight;
        return  (width  ===  0  &&  height  ===  0)  ||  (!
    jQuery.support.reliableHiddenOffsets  &&  (elem.style.display  ||  jQuery.css
    (  elem,  "display"  ))  ===  "none");
      };
      jQuery.expr.filters.visible  =  function(  elem  )  {
        return  !jQuery.expr.filters.hidden(  elem  );
      };
    }

    View Slide

  8. //Selectors
    1)  $(".child",  $parent).show();  (Scope)
    2)  $parent.find(".child").show();  (using  find())
    3)  $parent.children(".child").show();  (immediate  children)
    4)  $("#parent  >  .child").show();  (via  CSS  selector)
    5)  $("#parent  .child").show();  (same  as  2)
    A Look At Parents & Children

    View Slide

  9. Tip 3: Caching = Win.
    Each $(‘.whatever’) will re-run your search of
    the DOM and return a new collection
    Bad! - use caching! (ie. parents. find(‘.child’))
    You can then do whatever.show()/hide/stuff
    to your heart’s content.
    var  parents  =    $(‘.parents’);
    var  children  =  $(‘.parents’).find(‘.child’)  //bad

    View Slide

  10. Tip 4: Chaining
    Almost all jQuery methods return a jQuery
    Object and support chaining
    After you’ve run a method on your selection,
    you can continue running more!
    Less code, easier to write and it runs faster!
    var  parents  =    $(‘.parents’).doSomething().doSomethingElse();

    View Slide

  11. No-chaining vs. chaining
    //Without  chaining
    $(‘#notification’).fadeIn(‘slow’);
    $(‘#notification’).addClass(‘.activeNotification’);
    $(‘#notification’).css(‘marginLeft’,  ‘50px’);
    //With  chaining
    $(‘#notification’).fadeIn(‘slow’)
                                       .addClass(‘.activeNotification’)      
                                       .css(‘marginLeft’,  ‘50px’);

    View Slide

  12. Tip 5: Event Delegation
    Understand .bind(), .live() and .delegate() - do
    you REALLY know the differences?
    Delegates let you attach an event handler to a
    common parent of your elements rather than a
    discrete one to each of them
    Also fires for NEW DOM nodes too
    Use when binding same handler to multiple
    elements

    View Slide

  13. Tip 6: The DOM isn’t a Database!
    jQuery lets you treat it like one, but that
    doesn’t make it so
    Every DOM insertion is costly
    Minimize by building HTML strings and using
    single a single append() as late as possible
    Use detach() if doing heavy interaction with a
    node then re-insert it when done

    View Slide

  14. Quick Tip: Attaching Data
    A common way of attaching data is
    But this is significantly faster...
    $(‘#item’).data(key,value);
    $.data(‘#item’,  key,value);
                                       

    View Slide

  15. Tip 7: Avoid Loops. Nested DOM
    Selectors can perform better
    If not necessary, avoid loops. They’re slow in
    every programming language
    If possible, use the selector engine instead to
    address the elements that are needed
    There *are* places where loops can’t be
    substituted but try your best to optimize

    View Slide

  16. Loops
    //Slow!
    $('#menu  a.submenu').each(
        function(index){
          $(this).doSomething()
                           .doSomethingElse();
    });
    //Better!
    $('#menu a.submenu').doSomething()
    .doSomethingElse();

    View Slide

  17. Tip 8: Keep your code DRY
    /*Non-Dry*/
    /*Let's  store  some  default  values  in  an  array*/
    var  defaultSettings  =  {};
    defaultSettings['carModel']      =  'Mercedes';
    defaultSettings['carYear’]          =  2010;
    defaultSettings['carMiles']      =  5000;
    defaultSettings['carTint']        =  'Metallic  Blue';
     
    /*Let's  do  something  with  this  data  if  a  checkbox  is  clicked*/
    $('.someCheckbox').click(function(){  
                 
         if  (this.checked){                                
                   $('#input_carModel').val(activeSettings.carModel);
                   $('#input_carYear').val(activeSettings.carYear);
                   $('#input_carMiles').val(activeSettings.carMiles);
                   $('#input_carTint').val(activeSettings.carTint);
     
     }  else  {  
                                   
                   $('#input_carModel').val('');          
                   $('#input_carYear').val('');  
                   $('#input_carMiles').val('');
                   $('#input_carTint).val('');
     }
    });

    View Slide

  18. DRY-er code
    /*Dry*/
    $('.someCheckbox').click(function(){                
           var  checked  =  this.checked;
           /*
                   What  are  we  repeating?
                   1.  input_  precedes  each  field  name
                   2.  accessing  the  same  array  for  settings
                   3.  repeating  value  resets
       
                   What  can  we  do?
                   1.  programmatically  generate  the  field  names
                   2.  access  array  by  key  
                   3.  merge  this  call  using  terse  coding  (ie.  if  checked,  
                           set  a  value,  otherwise  don't)
           */    
                 $.each(['carModel',  'carYear',  'carMiles',  'carTint'],  function(i,key){
                                 $('#input_'  +  v).val(checked  ?  defaultSettings[key]  :  '');
                 });
    });

    View Slide

  19. When in doubt - Perf test!
    jsPerf.com - easy way to create tests comparing
    the perf of different JS snippets
    Uses Benchmark.js - a neat benchmarking
    utility that works cross-platform
    Easy to share your code or modify other tests

    View Slide

  20. Thats it!
    Thanks to Matt Baker over at WealthFront for his very useful reference material
    Twitter: @addyosmani / @addy_osmani
    For my blog: http://addyosmani.com
    GitHub: http://github.com/addyosmani

    View Slide