Upload
johndaviddalton
View
1.873
Download
2
Embed Size (px)
DESCRIPTION
I discuss topics like method forking, lazy defining of methods, JS minifiers, dos and don'ts of minification.
Citation preview
Coding for Performance
Parental Advisory : Hardcore Forking Action
By John-David Dalton
@jdalton ▪ [email protected] ▪ http://allyoucanleet.com
function times(iterator, context) { $R(0, this, true).each(iterator, context); return this;}
Reduce Abstraction
1.
function times(iterator, context) { var i = -1, length = this; while (++i < length) iterator.call(context, i, i); return length;}
Reduce Abstraction
2.
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.
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.
// 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.
// 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.
// true for IEreturn isHostType(window, 'ActiveXObject');
Feature Detection
7.
var xhr;
// Assumed to be IEIf (document.fileSize) { xhr = new ActiveXObject('Microsoft.XMLHTTP');} else { xhr = new XMLHttpRequest();}
Weak Object Inference
8.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Nay Context
// Prototype$$(‘.foo’);
// jQuery$(‘.foo’);
19.
Yay Context
// Prototypevar panel = $(‘panel’);panel.select(‘.foo’);
// jQueryvar panel = $(‘#panel’);panel.find(‘.foo’);
20.
Event Delegation != Magic
// Prototype usage$(‘myTable’).observe(‘click’, function(event) { if (event.findElement(‘td’)) { // do stuff }});
21.
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.
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.
Do
•Repeat use of the same variable names
•Store namespaced objects in variables
•Use variable lists
•Avoid compiled functions
24.
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.
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]