Web Optimization Summit: Coding for Performance

30
Coding for Performance Parental Advisory : Hardcore Forking Action By John-David Dalton @jdalton [email protected] http://allyoucanleet.com

description

I discuss topics like method forking, lazy defining of methods, JS minifiers, dos and don'ts of minification.

Transcript of Web Optimization Summit: Coding for Performance

Page 1: Web Optimization Summit: Coding for Performance

Coding for Performance

Parental Advisory : Hardcore Forking Action

By John-David Dalton

@jdalton ▪ [email protected] ▪ http://allyoucanleet.com

Page 2: Web Optimization Summit: Coding for Performance

function times(iterator, context) { $R(0, this, true).each(iterator, context); return this;}

Reduce Abstraction

1.

Page 3: Web Optimization Summit: Coding for Performance

function times(iterator, context) { var i = -1, length = this; while (++i < length) iterator.call(context, i, i); return length;}

Reduce Abstraction

2.

Page 4: Web Optimization Summit: Coding for Performance

function times(iterator, context) { var i = -1, length = this; if (context) { while (++i < length) iterator.call(context, i, i); } else { while (++i < length) iterator(i, i); } return length;}

Reduce Abstraction

3.

Page 5: Web Optimization Summit: Coding for Performance

Test Before Tapping Dat

•Feature Testing (Awesomest)

•Feature Detection (Pretty good)

•Weak Object Inference (Almost as bad as UA sniffing)

•User Agent Sniffing (Just say no!)

4.

Page 6: Web Optimization Summit: Coding for Performance

// true for Gecko and Webkitif ([ ][‘__proto__‘] === Array.prototype && { }['__proto__‘] === Object.prototype) { // test if it's writable and restorable var result, list = [], backup = list['__proto__']; list['__proto__'] = { }; result = typeof list.push === 'undefined'; list['__proto__'] = backup; return result && typeof list.push === 'function';}

Feature Testing

5.

Page 7: Web Optimization Summit: Coding for Performance

// Host objects can return type values that are different from their actual// data type. The objects we are concerned with usually return non-primitive// types of object, function, or unknown.// For example:// typeof document.createElement('div').offsetParent -> unknown// typeof document.createElement -> object// typeof Image.create -> stringisHostType = (function() { var NON_HOST_TYPES = { 'boolean': 1, 'number': 1, 'string': 1, 'undefined': 1 }; return function(object, property) { var type = typeof object[property]; return type === 'object' ? !!object[property] : !NON_HOST_TYPES[type]; };})();

Feature Detection

6.

Page 8: Web Optimization Summit: Coding for Performance

// true for IEreturn isHostType(window, 'ActiveXObject');

Feature Detection

7.

Page 9: Web Optimization Summit: Coding for Performance

var xhr;

// Assumed to be IEIf (document.fileSize) { xhr = new ActiveXObject('Microsoft.XMLHTTP');} else { xhr = new XMLHttpRequest();}

Weak Object Inference

8.

Page 10: Web Optimization Summit: Coding for Performance

function contains(element, descendant) { if (element.compareDocumentPosition) { return (descendant .compareDocumentPosition(element) & 8) === 8; } if (element.contains) { return element !== descendant && element.contains(element); } while (descendant = descendant.parentNode) { if (descendant == element) return true; } return false;}

Fork like Rabbits

9.

Page 11: Web Optimization Summit: Coding for Performance

var contains = function(element, descendant) { while (descendant = descendant.parentNode) { if (descendant === element) return true; } return false;};if (isHostType(docEl, 'compareDocumentPosition')) { contains = function(element, descendant) { /* DOCUMENT_POSITION_CONTAINS = 0x08 */ return (descendant .compareDocumentPosition(element) & 8) === 8; };}else if (isHostType(docEl, 'contains')) { contains = function(element, descendant) { return element !== descendant && element.contains(descendant); };}

Fork like Robots

10.

Page 12: Web Optimization Summit: Coding for Performance

var contains = function(element, descendant) { while (descendant = descendant.parentNode) { if (descendant === element) return true; } return false;};

if (isHostType(docEl, 'compareDocumentPosition')) { contains = function(element, descendant) { /* DOCUMENT_POSITION_CONTAINS = 0x08 */ return (descendant .compareDocumentPosition(element) & 8) === 8; };}else if (isHostType(docEl, 'contains')) { contains = function(element, descendant) { return element !== descendant && element.contains(descendant); };}

Fork like Hobbits

11.

Page 13: Web Optimization Summit: Coding for Performance

var contains = function(element, descendant) { while (descendant = descendant.parentNode) { if (descendant === element) return true; } return false;};

if (isHostObject(docEl, 'compareDocumentPosition')) { contains = function(element, descendant) { /* DOCUMENT_POSITION_CONTAINS = 0x08 */ return (descendant .compareDocumentPosition(element) & 8) === 8; };}

else if (isHostType(docEl, 'contains')) { contains = function(element, descendant) { return element !== descendant && element.contains(descendant); };}

But don't fork Marsellus Wallace !

12.

Page 14: Web Optimization Summit: Coding for Performance

plugin.getRelatedTarget = function getRelatedTarget() {

var setRelatedTarget = function(object, value) { object.getRelatedTarget = createGetter('getRelatedTarget', value); return value; },

getRelatedTarget = function getRelatedTarget() { var node = this.raw && this.raw.relatedTarget; return setRelatedTarget(this, node && fromElement(node)); };

// fired events have no raw if (!this.raw) { return setRelatedTarget(this, null); } // for IE if (typeof this.raw.relatedTarget === 'undefined’) { getRelatedTarget = function getRelatedTarget() { var node = null, event = this.raw; switch (event && event.type) { case 'mouseover': node = fromElement(event.fromElement); case 'mouseout': node = fromElement(event.toElement); } return setRelatedTarget(this, node); }; } plugin.getRelatedTarget = getRelatedTarget; return this.getRelatedTarget();

};

Forking + Lazy Load

13.

Page 15: Web Optimization Summit: Coding for Performance

plugin.getRelatedTarget = function getRelatedTarget() {

var setRelatedTarget = function(object, value) { object.getRelatedTarget = createGetter('getRelatedTarget', value); return value; }, getRelatedTarget = function getRelatedTarget() { var node = this.raw && this.raw.relatedTarget; return setRelatedTarget(this, node && fromElement(node)); };

// fired events have no raw if (!this.raw) { return setRelatedTarget(this, null); } // for IE if (typeof this.raw.relatedTarget === 'undefined') { getRelatedTarget = function getRelatedTarget() { var node = null, event = this.raw; switch (event && event.type) { case 'mouseover': node = fromElement(event.fromElement); case 'mouseout': node = fromElement(event.toElement); } return setRelatedTarget(this, node); }; }

Forking + Lazy Load

14.

Page 16: Web Optimization Summit: Coding for Performance

plugin.getRelatedTarget = function getRelatedTarget() { var setRelatedTarget = function(object, value) { object.getRelatedTarget = createGetter('getRelatedTarget', value); return value; },

getRelatedTarget = function getRelatedTarget() { var node = this.raw && this.raw.relatedTarget; return setRelatedTarget(this, node && fromElement(node)); }; // fired events have no raw if (!this.raw) { return setRelatedTarget(this, null); } // for IE if (typeof this.raw.relatedTarget === 'undefined') { getRelatedTarget = function getRelatedTarget() { var node = null, event = this.raw; switch (event && event.type) { case 'mouseover': node = fromElement(event.fromElement); case 'mouseout': node = fromElement(event.toElement); } return setRelatedTarget(this, node); }; }

Forking + Lazy Load

15.

Page 17: Web Optimization Summit: Coding for Performance

getRelatedTarget = function getRelatedTarget() { var node = this.raw && this.raw.relatedTarget; return setRelatedTarget(this, node && fromElement(node)); };

// fired events have no raw if (!this.raw) { return setRelatedTarget(this, null); } // for IE

if (typeof this.raw.relatedTarget === 'undefined') { getRelatedTarget = function getRelatedTarget() { var node = null, event = this.raw; switch (event && event.type) { case 'mouseover': node = fromElement(event.fromElement); case 'mouseout': node = fromElement(event.toElement); } return setRelatedTarget(this, node); }; } plugin.getRelatedTarget = getRelatedTarget;

Forking + Lazy Load

16.

Page 18: Web Optimization Summit: Coding for Performance

plugin.getRelatedTarget = function getRelatedTarget() { var setRelatedTarget = function(object, value) { object.getRelatedTarget = createGetter('getRelatedTarget', value); return value; },

getRelatedTarget = function getRelatedTarget() { var node = this.raw && this.raw.relatedTarget; return setRelatedTarget(this, node && fromElement(node)); };

// fired events have no raw if (!this.raw) { return setRelatedTarget(this, null); } // for IE if (typeof this.raw.relatedTarget === 'undefined’) { getRelatedTarget = function getRelatedTarget() { var node = null, event = this.raw; switch (event && event.type) { case 'mouseover': node = fromElement(event.fromElement); case 'mouseout': node = fromElement(event.toElement); } return setRelatedTarget(this, node); }; }

plugin.getRelatedTarget = getRelatedTarget; return this.getRelatedTarget();};

Forking + Lazy Load

17.

Page 19: Web Optimization Summit: Coding for Performance

var cache = { }, reHyphenated = /-([a-z])/gi, uid = +new Date;

function toUpperCase(match, letter) { return letter.toUpperCase();}

function camelCase(string) { var key = uid + string; return cache[key] || (cache[key] = string.replace(reHyphenated, toUpperCase));}

Memoize

18.

Page 20: Web Optimization Summit: Coding for Performance

Nay Context

// Prototype$$(‘.foo’);

// jQuery$(‘.foo’);

19.

Page 21: Web Optimization Summit: Coding for Performance

Yay Context

// Prototypevar panel = $(‘panel’);panel.select(‘.foo’);

// jQueryvar panel = $(‘#panel’);panel.find(‘.foo’);

20.

Page 22: Web Optimization Summit: Coding for Performance

Event Delegation != Magic

// Prototype usage$(‘myTable’).observe(‘click’, function(event) { if (event.findElement(‘td’)) { // do stuff }});

21.

Page 23: Web Optimization Summit: Coding for Performance

Minifiers

•Packer 3.1 (Old School, You’re my boy, Blue!)

•YUI Compressor (Been around the block)

•Closure Compiler (Googtastic)

•JSMin (Ported to lots of languages)

22.

Page 24: Web Optimization Summit: Coding for Performance

What’s Cool

// code like thisemit(‘I will be ’ + ‘concated by ‘ + ‘pirate magic’);

// will be valmorphanize intoemit(‘I will be concated by pirate magic’);

23.

Page 25: Web Optimization Summit: Coding for Performance

Do

•Repeat use of the same variable names

•Store namespaced objects in variables

•Use variable lists

•Avoid compiled functions

24.

Page 26: Web Optimization Summit: Coding for Performance

Do Not

•Become anal about semi-colons

•Replace all property names with variables

•Use short non-descriptive variable names

•Tug on Superman’s cape

25.

Page 27: Web Optimization Summit: Coding for Performance
Page 28: Web Optimization Summit: Coding for Performance
Page 29: Web Optimization Summit: Coding for Performance
Page 30: Web Optimization Summit: Coding for Performance

Links

http://github.com/jdalton/fusejs

http://developer.yahoo.com/yui/compressor/

http://code.google.com/closure/compiler/

http://www.crockford.com/javascript/jsmin.html

http://github.com/rgrove/jsmin-php/

http://base2.googlecode.com/svn/trunk/src/apps/packer/packer.html

http://code.google.com/p/base2/source/browse/#svn/trunk/src/apps/packer

Twitter: @jdalton @fusejs

Email: [email protected]