Slide 1

Slide 1 text

jQuery Performance Tips & Tricks Addy Osmani, Jan 2011

Slide 2

Slide 2 text

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.

Slide 3

Slide 3 text

I <3 jQuery

Slide 4

Slide 4 text

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.

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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.

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

//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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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('');  } });

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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