JSConf: All You Can Leet

Preview:

DESCRIPTION

My JSConf slides.

Citation preview

All You Can LeetA heaping helping of performance,

selector engines, & sandbox natives

By John-David Dalton

@jdalton ▪ john@fusejs.com ▪ http://allyoucanleet.com

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

Performance

Reduce Abstraction

Performance

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

Reduce Abstraction

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

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

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

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

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

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

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

•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

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

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

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

CSS 3 Selector Tests: LegacySelector Engines

CSS 3 Selector Tests: SizzleSelector Engines

CSS 3 Selector Tests: NWMatcherSelector Engines

Match Maker[ event delegation; higher score is better ]

Selector Engines

Performance[ higher score is better ]

Selector Engines

Performance[ higher score is better ]

Selector Engines

Make the Switch

rake dist SELECTOR_ENGINE = nwmatcher

Selector Engines

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

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

// 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

// 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

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

Supported Natives

•fuse.Number

•fuse.Object

•fuse.RegExp

•fuse.String

•fuse.Array

•fuse.Boolean

•fuse.Date

•fuse.Function

Sandbox Natives

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

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

FuseJS

Fuse JavaScript Framework

FuseJS

Browsers Tested

•IE 6+

•Firefox 1.5+

•Chrome 1+

•Konqueror 4.2.2

•Opera 9.25+

•Safari 2.0+

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

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

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

FuseJS

Performance[ lower score is better ]

FuseJS

Performance[ lower score is better ]

FuseJS

Performance[ IE8 - lower score is better ]

FuseJS

Performance[ lower score is better ]

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: john@fusejs.com