Slide 1

Slide 1 text

How DRY impacts JavaScript performance // Faster JavaScript execution for the lazy developer Mathias Bynens – Velocity Europe, November 2011

Slide 2

Slide 2 text

@mathias

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

JavaScript & performance

Slide 5

Slide 5 text

JavaScript & performance What about the actual run-time performance on the client side?

Slide 6

Slide 6 text

DRY flic.kr/p/2ZGCT

Slide 7

Slide 7 text

WET flic.kr/p/5Jnj7Q

Slide 8

Slide 8 text

“DRY leads to readable, maintainable code”

Slide 9

Slide 9 text

DRY JavaScript improves performance …if you do it right

Slide 10

Slide 10 text

So, where to avoid repetition?

Slide 11

Slide 11 text

What’s slow in JavaScript?

Slide 12

Slide 12 text

What’s slow in JavaScript? 1. The DOM

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

DOM manipulation // Create the element in memory var el = document.createElement('p'); // Insert the element into the DOM document.body.appendChild(el);

Slide 16

Slide 16 text

DOM manipulation …

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

DOM manipulation …

Slide 20

Slide 20 text

DOM manipulation var p = document.createElement('p'), i = 4; while (i--) { // Add four

elements document.body.appendChild(p.cloneNode(false)); }

Slide 21

Slide 21 text

DOM manipulation var frag = document.createDocumentFragment(), p = document.createElement('p'), i = 4; while (i--) { // Add four

elements frag.appendChild(p.cloneNode(false)); } document.body.appendChild(frag);

Slide 22

Slide 22 text

Function calls // Function declaration function foo(bar) { return bar; } // Function call foo('something');

Slide 23

Slide 23 text

Function calls alert('foo'); document.getElementById('foo'); $('#foo');

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Property lookups var obj = { 'x': 42, 'y': { 'foo': 'bar' } }; obj.x; // 42 obj.y.foo; // 'bar'

Slide 28

Slide 28 text

Property lookups document.title dojo.query(…) YAHOO.util.Dom.get(…)

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

Scope lookups var foo = 42; foo; // no scope lookup

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Scope lookups var foo = 42; (function() { (function() { foo; // two scope lookups }()); }());

Slide 36

Slide 36 text

Scope lookups

Slide 37

Slide 37 text

Scope lookups var foo = 42; (function(foo) { (function(foo) { foo; // ZOMG, no scope lookups!!1 }(foo)); }(foo));

Slide 38

Slide 38 text

Scope lookups

Slide 39

Slide 39 text

Scope lookups (function() { // every time you use `window` // or `document` here // that’s a scope lookup }());

Slide 40

Slide 40 text

Scope lookups (function() { var doc = document, win = window; // lookup once, then cache }());

Slide 41

Slide 41 text

Scope lookups (function(win, doc) { // use `win` and `doc` here // no scope lookups // no performance penalty! }(this, document));

Slide 42

Slide 42 text

Recap: what’s slow in JavaScript?

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

Especially when used inside…

Slide 47

Slide 47 text

Especially when used inside… • Loops

Slide 48

Slide 48 text

Especially when used inside… • Loops • Intervals

Slide 49

Slide 49 text

Especially when used inside… • Loops • Intervals • Handlers for events that fire frequently

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

typeof performance != 'the whole story'

Slide 54

Slide 54 text

tips & tricks (not really)

Slide 55

Slide 55 text

New objects var obj = new Object(); obj.x = 42; obj.y = 'foo'; obj.z = false;

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

Avoid switch switch(foo) { case 'alpha': // do X break; case 'beta': // do Y break; default: // do Z break; }

Slide 60

Slide 60 text

Avoid switch var switchObj = { 'alpha': function() { // do X }, 'beta': function() { // do Y }, '_default': function() { // do Z } }; (switchObj.hasOwnProperty(foo) && switchObj[foo] || switchObj._default)(args);

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

Don’t use jQuery for everything $('.foo').click(function() { this.id; this.href; this.checked; this.value; // etc. });

Slide 63

Slide 63 text

jQuery document ready $(document).ready(function() { // teh coads });

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

jQuery document ready (function() { // move s to the bottom // and just use an IIFE* }()); // * unless you use .appendChild() / .innerHTML on document.documentElement or document.body: http://mths.be/ieoa

Slide 68

Slide 68 text

jQuery collection size $('.foo').size(); // NO.

Slide 69

Slide 69 text

jQuery collection size // jQuery source: $.fn.size = function() { return this.length; }; // …so, just use: $('.foo').length;

Slide 70

Slide 70 text

Use context $('#foo .bar').addClass('baz'); $('#foo .qux').hide(); $('#foo input').removeClass('wut');

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

this.location = 'http://jsperf.com/'

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

Questions? @mathias