How DRY impacts JavaScript performance // Faster JavaScript execution for the lazy developer

How DRY impacts JavaScript performance // Faster JavaScript execution for the lazy developer

The slides for my Velocity Europe 2011 talk.

24e08a9ea84deb17ae121074d0f17125?s=128

Mathias Bynens

November 17, 2011
Tweet

Transcript

  1. How DRY impacts JavaScript performance // Faster JavaScript execution for

    the lazy developer Mathias Bynens – Velocity Europe, November 2011
  2. @mathias

  3. JavaScript & performance Rule #1: nothing to do with JS

  4. JavaScript & performance

  5. JavaScript & performance What about the actual run-time performance on

    the client side?
  6. DRY flic.kr/p/2ZGCT

  7. WET flic.kr/p/5Jnj7Q

  8. “DRY leads to readable, maintainable code”

  9. DRY JavaScript improves performance …if you do it right

  10. So, where to avoid repetition?

  11. What’s slow in JavaScript?

  12. What’s slow in JavaScript? 1. The DOM

  13. What’s slow in JavaScript? 1. The DOM 2. Function calls

  14. What’s slow in JavaScript? 1. The DOM 2. Function calls

    3. Lookups
  15. DOM manipulation // Create the element in memory var el

    = document.createElement('p'); // Insert the element into the DOM document.body.appendChild(el);
  16. DOM manipulation <body> … <div> <p></p> </div> </body>

  17. DOM manipulation var div = document.createElement('div'), p = document.createElement('p'); //

    Bad document.body.appendChild(div); div.appendChild(p);
  18. DOM manipulation var div = document.createElement('div'), p = document.createElement('p'); //

    Better div.appendChild(p); document.body.appendChild(div);
  19. DOM manipulation <body> … <p></p> <p></p> <p></p> <p></p> </body>

  20. DOM manipulation var p = document.createElement('p'), i = 4; while

    (i--) { // Add four <p> elements document.body.appendChild(p.cloneNode(false)); }
  21. DOM manipulation var frag = document.createDocumentFragment(), p = document.createElement('p'), i

    = 4; while (i--) { // Add four <p> elements frag.appendChild(p.cloneNode(false)); } document.body.appendChild(frag);
  22. Function calls // Function declaration function foo(bar) { return bar;

    } // Function call foo('something');
  23. Function calls alert('foo'); document.getElementById('foo'); $('#foo');

  24. Function calls $('.foo').show(); // other stuff… $('.foo').hide();

  25. Function calls var $foo = $('.foo'); $foo.show(); // other stuff…

    $foo.hide();
  26. Function calls var $foo = $('.foo').show(); // other stuff… $foo.hide();

  27. Property lookups var obj = { 'x': 42, 'y': {

    'foo': 'bar' } }; obj.x; // 42 obj.y.foo; // 'bar'
  28. Property lookups document.title dojo.query(…) YAHOO.util.Dom.get(…)

  29. Property lookups var foo = YAHOO.util.Dom.get('foo'), bar = YAHOO.util.Dom.get('bar'), baz

    = YAHOO.util.Dom.get('baz'), qux = YAHOO.util.Dom.get('qux');
  30. Property lookups var get = YAHOO.util.Dom.get, foo = get('foo'), bar

    = get('bar'), baz = get('baz'), qux = get('qux');
  31. Array item lookups var elems = document.getElementsByTagName('p'), length = elems.length;

    while (length--) { if (elems[length].className == 'foo') { // do something with elems[length] elems[length].innerHTML = 'LOLWAT'; } }
  32. Array item lookups var elems = document.getElementsByTagName('p'), length = elems.length,

    elem; while (length--) { elem = elems[length]; if (elem.className == 'foo') { // do something with elem elem.innerHTML = 'LOLWAT'; } }
  33. Scope lookups var foo = 42; foo; // no scope

    lookup
  34. Scope lookups var foo = 42; (function() { foo; //

    one scope lookup }()); // IIFE – see http://mths.be/iife
  35. Scope lookups var foo = 42; (function() { (function() {

    foo; // two scope lookups }()); }());
  36. Scope lookups

  37. Scope lookups var foo = 42; (function(foo) { (function(foo) {

    foo; // ZOMG, no scope lookups!!1 }(foo)); }(foo));
  38. Scope lookups

  39. Scope lookups (function() { // every time you use `window`

    // or `document` here // that’s a scope lookup }());
  40. Scope lookups (function() { var doc = document, win =

    window; // lookup once, then cache }());
  41. Scope lookups (function(win, doc) { // use `win` and `doc`

    here // no scope lookups // no performance penalty! }(this, document));
  42. Recap: what’s slow in JavaScript?

  43. Recap: what’s slow in JavaScript? 1. The DOM

  44. Recap: what’s slow in JavaScript? 1. The DOM 2. Function

    calls
  45. Recap: what’s slow in JavaScript? 1. The DOM 2. Function

    calls 3. Lookups
  46. Especially when used inside…

  47. Especially when used inside… • Loops

  48. Especially when used inside… • Loops • Intervals

  49. Especially when used inside… • Loops • Intervals • Handlers

    for events that fire frequently
  50. It happens to the best! // Don’t do this: $(window).scroll(function()

    { $('.foo').something(); });
  51. It happens to the best! // Don’t do this: $(window).scroll(function()

    { $('.foo').something(); });
  52. It happens to the best! // Don’t do this: $(window).scroll(function()

    { $('.foo').something(); }); // See http://mths.be/azs
  53. typeof performance != 'the whole story'

  54. tips & tricks (not really)

  55. New objects var obj = new Object(); obj.x = 42;

    obj.y = 'foo'; obj.z = false;
  56. New objects var obj = { 'x': 42, 'y': 'foo',

    'z': false };
  57. New arrays var arr = new Array(); arr.push(42); arr.push('foo'); arr.push(false);

  58. New arrays var arr = [ 42, 'foo', false ];

  59. Avoid switch switch(foo) { case 'alpha': // do X break;

    case 'beta': // do Y break; default: // do Z break; }
  60. Avoid switch var switchObj = { 'alpha': function() { //

    do X }, 'beta': function() { // do Y }, '_default': function() { // do Z } }; (switchObj.hasOwnProperty(foo) && switchObj[foo] || switchObj._default)(args);
  61. Don’t use jQuery for everything $('.foo').click(function() { $(this).prop('id'); // same

    as this, before jQuery 1.6: // $(this).attr('id'); // also `href`, `checked`, `value`… });
  62. Don’t use jQuery for everything $('.foo').click(function() { this.id; this.href; this.checked;

    this.value; // etc. });
  63. jQuery document ready $(document).ready(function() { // teh coads });

  64. jQuery document ready $().ready(function() { // heh });

  65. jQuery document ready $.fn.ready(function() { // not pretty, but fastest

    solution });
  66. jQuery document ready $(function() { // moar sexy, but slower

    });
  67. jQuery document ready (function() { // move <script>s to the

    bottom // and just use an IIFE* }()); // * unless you use .appendChild() / .innerHTML on document.documentElement or document.body: http://mths.be/ieoa
  68. jQuery collection size $('.foo').size(); // NO.

  69. jQuery collection size // jQuery source: $.fn.size = function() {

    return this.length; }; // …so, just use: $('.foo').length;
  70. Use context $('#foo .bar').addClass('baz'); $('#foo .qux').hide(); $('#foo input').removeClass('wut');

  71. Use context var $foo = $('#foo'); $('.bar', $foo).addClass('baz'); $('.qux', $foo).hide();

    $('input', $foo).removeClass('wut');
  72. this.location = 'http://jsperf.com/'

  73. http://jsperf.com/browse/mathias-bynens

  74. Questions? @mathias