39
All You Can Leet A heaping helping of performance, selector engines, & sandbox natives By John-David Dalton @jdalton [email protected] http://allyoucanleet.com

JSConf: All You Can Leet

Embed Size (px)

DESCRIPTION

My JSConf slides.

Citation preview

Page 1: JSConf: All You Can Leet

All You Can LeetA heaping helping of performance,

selector engines, & sandbox natives

By John-David Dalton

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

Page 2: JSConf: All You Can Leet

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

Performance

Reduce Abstraction

Page 3: JSConf: All You Can Leet

Performance

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

Reduce Abstraction

Page 4: JSConf: All You Can Leet

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

Page 5: JSConf: All You Can Leet

function isHostObject(object, property) { var type = typeof object[property]; return type === 'object' ? !!object[property] : !/^(boolean|number|string|undefined)$/.test(type);}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 (isHostObject(docEl, 'contains')) { contains = function(element, descendant) { return element !== descendant && element.contains(descendant); }

Performance

Fork like Rabbits

Page 6: JSConf: All You Can Leet

var type = typeof object[property]; return type === 'object' ? !!object[property] : !/^(boolean|number|string|undefined)$/.test(type);}

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 (isHostObject(docEl, 'contains')) { contains = function(element, descendant) { return element !== descendant && element.contains(descendant); };}

Performance

Fork like Robots

Page 7: JSConf: All You Can Leet

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 (isHostObject(docEl, 'contains')) { contains = function(element, descendant) { return element !== descendant && element.contains(descendant); };}

Performance

Fork like Hobbits

Page 8: JSConf: All You Can Leet

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 (isHostObject(docEl, 'contains')) { contains = function(element, descendant) { return element !== descendant && element.contains(descendant); };}

But don't fork Marsellus Wallace !

Performance

Page 9: JSConf: All You Can Leet

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

Performance

Page 10: JSConf: All You Can Leet

Choose Your Engine

•base2

•DomAssistant

•IDQuery

•LlamaLab

•MyLibrary

•Sly

•uuQuery

•YASS

•YUI

•Acme (Dojo)

•DomQuery (ExtJS)

•NWMatcher (FuseJS, Prototype)

•Sizzle (jQuery, MochiKit, Prototype)

•Slick (MooTools)

Selector Engines

Page 11: JSConf: All You Can Leet

•base2

•DomAssistant

•IDQuery

•LlamaLab

•MyLibrary

•Sly

•uuQuery

•YASS

•YUI

•Acme (Dojo)

•DomQuery (ExtJS)

•NWMatcher (FuseJS, Prototype)

•Sizzle (jQuery, MochiKit, Prototype)

•Slick (MooTools)

Dare to Compare

Selector Engines

Page 12: JSConf: All You Can Leet

NWMatcher Chrome 1+ Firefox 1.5+ IE 6+ Opera 9.0+ Safari 2.0+

Legacy Chrome 1+ Firefox 1.5+ IE 6+ Opera 9.25+ Safari 2.0.4+

Sizzle Chrome 1+ Firefox 2.0+ IE 6+ Opera 9.0+ Safari 3.0+

Prototype 1.6.1+

* 1.6.0.3 supports Safari 2.0+

Compatible Source ▪ Compatible ▪ Possible Compatibility ▪ Failed Compatibility

Browser Support

Selector Engines

Page 13: JSConf: All You Can Leet

E E#fooId E.fooClass E F E > F E + F F ~ F F[foo] F[foo="bar"] E[foo^="bar"] E[foo$="bar"] E[foo*="bar"] E[foo~="bar"] E[foo|="en"] E:root E:empty E:nth-child(n) E:nth-of-type(n) E:nth-last-child(n)

NWMatcherSizzle Prototype 1.6.1+

E:nth-last-of-type(n) E:first-child E:last-child E:only-child E:first-of-type E:last-of-type E:only-of-type E:not(s) E:active E:focus E:enabled E:disabled E:checked E:link E:visited E:target E:lang(t)

E:nth-last-of-type(n) E:first-child E:last-child E:only-child E:first-of-type E:last-of-type E:only-of-type E:not(s) E:active E:focus E:enabled E:disabled E:checked E:link E:visited E:target E:lang(t)

E:nth-last-of-type(n) E:first-child E:last-child E:only-child E:first-of-type E:last-of-type E:only-of-type E:not(s) E:active E:focus E:enabled E:disabled E:checked E:link E:visited E:target E:lang(t)

Not Supported ▪ Supported ▪ Not Supported + Failed Compatibility

E E#fooId E.fooClass E F E > F E + F F ~ F F[foo] F[foo="bar"] E[foo^="bar"] E[foo$="bar"] E[foo*="bar"] E[foo~="bar"] E[foo|="en"] E:root E:empty E:nth-child(n) E:nth-of-type(n) E:nth-last-child(n)

E E#fooId E.fooClass E F E > F E + F F ~ F F[foo] F[foo="bar"] E[foo^="bar"] E[foo$="bar"] E[foo*="bar"] E[foo~="bar"] E[foo|="en"] E:root E:empty E:nth-child(n) E:nth-of-type(n) E:nth-last-child(n)

Legacy

Selector Engines

Selector Support

Page 14: JSConf: All You Can Leet

NWMatcherSizzle

QuerySelectorAll Bug Fixes

Prototype 1.6.1+

1. Quirks className case-sensitivity

2. Quirks mixed case className

3. :disabled :enabled on inputtype="hidden”

4. :link matching non-hyperlinks

5. :target support

6. Matching ^="" or $=""

7. Source attribute values

1. Quirks uppercase className

1. Quirks className case-insensitivity

Legacy

Selector Engines

Page 15: JSConf: All You Can Leet

CSS 3 Selector Tests: LegacySelector Engines

Page 16: JSConf: All You Can Leet

CSS 3 Selector Tests: SizzleSelector Engines

Page 17: JSConf: All You Can Leet

CSS 3 Selector Tests: NWMatcherSelector Engines

Page 18: JSConf: All You Can Leet

Match Maker[ event delegation; higher score is better ]

Selector Engines

Page 19: JSConf: All You Can Leet

Performance[ higher score is better ]

Selector Engines

Page 20: JSConf: All You Can Leet

Performance[ higher score is better ]

Selector Engines

Page 21: JSConf: All You Can Leet

Make the Switch

rake dist SELECTOR_ENGINE = nwmatcher

Selector Engines

Page 22: JSConf: All You Can Leet

The Problem

Array.prototype.size = function() { return this.length;};

var arr = [1, 2, 3];arr.size(); // 3

// Excluding the use of newer ES5 methods like// Object.defineProperty() when defining new properties// the internal [[DefineOwnProperty]] method is called with// a property descriptor containing [[Enumerable]] true.for (var i in arr) { // i is 0, 1, 2, `size`}

Sandbox Natives

Page 23: JSConf: All You Can Leet

The Problem

// framework X defines a methodFunction.prototype.defer = function() { var fn = this, args = arguments; return window.setTimeout(function() { fn.apply(fn, args); }, 10);};

// framework Y paves previous method with their ownFunction.prototype.defer = function(millis, thisArg, args) { var fn = this; return window.setTimeout(function() { fn.apply(thisArg, args); }, millis);};

Sandbox Natives

Page 24: JSConf: All You Can Leet

// framework X defines a methodArray.prototype.reduce = function() { return this.length > 1 ? this : this[0];};

// Later, a different implementation is added to ECMAScript// 15.4.4.21 Array#reduce ( callbackfn [ , initialValue ] )

// returns [1, 2, 3] instead of 6[1, 2, 3].reduce(function(prevValue, value) { return prevValue + value;});

The Problem

Sandbox Natives

Page 25: JSConf: All You Can Leet

// Sandbox natives to the rescuefuse.Array.prototype.size = function() { return fuse.Number(this.length);};

var arr = fuse.Array(1, 2, 3);arr.size(); // 3

// won't extend the global Array constructortypeof window.Array.prototype.size; // undefined

The Solution

Sandbox Natives

Page 26: JSConf: All You Can Leet

Browsers Tested

•IE 5.5+

•Firefox 1.5+

•Chrome 1+

•Konqueror 4.2.2+

•Opera 9.0+

•Safari 2.0+

Various JavaScript Engines•SpiderMonkey

•SquirrelFish (& Extreme)

•Tamarin

•TraceMonkey

•V8

•Carakan

•JaegerMonkey

•JavaScriptCore

•KJS

•Nitro

•Rhino

Sandbox Natives

Page 27: JSConf: All You Can Leet

Supported Natives

•fuse.Number

•fuse.Object

•fuse.RegExp

•fuse.String

•fuse.Array

•fuse.Boolean

•fuse.Date

•fuse.Function

Sandbox Natives

Page 28: JSConf: All You Can Leet

Usage

var str = fuse.String('bacon');

// sandbox natives cannot be primitivestypeof str; // object

// kinda like calling the global String constructortypeof new String('bacon'); // object

// internal [[Class]] is still [object String]({ }).toString.call(str);

// chaining works toostr.split('').join('').capitalize(); // Bacon

Sandbox Natives

Page 29: JSConf: All You Can Leet

What's Cool

// multiple sandboxed nativesfuse.Array;

fuse.dom.NodeList = (new fuse.Fusebox).Array;

// jQuery syntax with real arraysfuse.query('.tabs').addClassName('.active').show();

Sandbox Natives

Page 30: JSConf: All You Can Leet

FuseJS

Fuse JavaScript Framework

Page 31: JSConf: All You Can Leet

FuseJS

Browsers Tested

•IE 6+

•Firefox 1.5+

•Chrome 1+

•Konqueror 4.2.2

•Opera 9.25+

•Safari 2.0+

Page 32: JSConf: All You Can Leet

FuseJS

•Sandbox Native[ better 3rd party & browser support ]

•Performance[ Reduced abstraction & fork methods by browser features ]

•Zero Browser Sniffs[ feature detection, feature testing, object inference ]

•Framework Emulation[ PrototypeJS at beta, others later ]

•Debug Friendly[ console.log(fuse.Number(3).times); // times(callback, thisArg) ]

Features

Page 33: JSConf: All You Can Leet

FuseJS

•Modular[ less abstraction, custom builds ]

•Selector Engines[ Acme, DomQuery, NWMatcher, Peppy, Sizzle, Slick, Sly ]

•Quirks mode support[ dimensions, positioning ]

•DOM + Event decorators[ better 3rd party & browser support ]

•Cross iframe compatible[ fuse(iframeDoc).query('.widget') ]

Features

Page 34: JSConf: All You Can Leet

FuseJS

•Enforce FIFO Event Observer Order[ cross-browser and fixes edge cases ]

•Back-Forward Cache[ better performance between page navigation ]

•No Expandos Added in IE[ avoids unnecessary redraws ]

•Method Generics[ fuse.Array.slice(arr, 0) ]

•Separation of DOM Properties & Attributes[ fuse.dom.Element.plugin.getAttribute ]

Features

Page 35: JSConf: All You Can Leet

FuseJS

Performance[ lower score is better ]

Page 36: JSConf: All You Can Leet

FuseJS

Performance[ lower score is better ]

Page 37: JSConf: All You Can Leet

FuseJS

Performance[ IE8 - lower score is better ]

Page 38: JSConf: All You Can Leet

FuseJS

Performance[ lower score is better ]

Page 39: JSConf: All You Can Leet

Links

http://github.com/jdalton/fusejs

http://github.com/jdalton/fusebox

http://github.com/dperini/nwmatcher

http://fusejs.com

http://fusejs.com/nwmatcher/match/

http://fusejs.com/prototypejs/speed/?css=yahoo

http://javascript.nwbox.com/NWMatcher/release/test/css3-compat/

Twitter: @jdalton @fusejs

Email: [email protected]