139

Beyond DOMReady: Ultra High-Performance Javascript

Embed Size (px)

DESCRIPTION

Leverage patterns of large-scale JS – such as modules, publish-subscribe and delegation – to achieve extreme performance without sacrificing maintainability.

Citation preview

Page 1: Beyond DOMReady: Ultra High-Performance Javascript
Page 2: Beyond DOMReady: Ultra High-Performance Javascript

this is not a TEDTALK

Page 3: Beyond DOMReady: Ultra High-Performance Javascript

not high-performance javascript

Page 4: Beyond DOMReady: Ultra High-Performance Javascript

ultra high-performance javascript

Page 5: Beyond DOMReady: Ultra High-Performance Javascript

what is ultra high-performance?

Page 6: Beyond DOMReady: Ultra High-Performance Javascript

made possible via

• fast file loading.

• small file sizes.

• avoiding DOM bottlenecks.

Page 7: Beyond DOMReady: Ultra High-Performance Javascript

what high-performance looks like

Page 8: Beyond DOMReady: Ultra High-Performance Javascript

hint: in general it looks awful

Page 9: Beyond DOMReady: Ultra High-Performance Javascript

high-performance != maintainability

the elements of high-performance are usually at odds with best practices in maintainability…

Page 10: Beyond DOMReady: Ultra High-Performance Javascript

an approach

start with maintainability, and achieve high-performance by building it in via automated processes.

Page 11: Beyond DOMReady: Ultra High-Performance Javascript

large-scale JS

to write maintainable code, look at the patterns used by other large-scale JS frameworks:

Page 12: Beyond DOMReady: Ultra High-Performance Javascript

large-scale JS

• separate code into modules, each of which accomplishes a single function.

• expose the module through an interface.

Page 13: Beyond DOMReady: Ultra High-Performance Javascript

modularprogramming

Page 14: Beyond DOMReady: Ultra High-Performance Javascript

module pattern

module consists of 3 parts:

Page 15: Beyond DOMReady: Ultra High-Performance Javascript

module pattern

module consists of 3 parts:

1. function (what it does)

Page 16: Beyond DOMReady: Ultra High-Performance Javascript

var _transform = function(sel) {$(sel).toggleClass('robot');

}

Page 17: Beyond DOMReady: Ultra High-Performance Javascript

// wrapped in a self-executing functionvar transformer = function() {

var _transform = function(sel) {$(sel).toggleClass('robot');

}}();

Page 18: Beyond DOMReady: Ultra High-Performance Javascript

module pattern

module consists of 3 parts:

1. function (what it does)

2. dependencies (what it needs)

Page 19: Beyond DOMReady: Ultra High-Performance Javascript

var transformer = function($) {var _transform = function(sel) {

$(sel).toggleClass('robot');}

}(jQuery);

Page 20: Beyond DOMReady: Ultra High-Performance Javascript

module pattern

module consists of 3 parts:

1. function (what it does)

2. dependencies (what it needs)

3. interface (what it returns)

Page 21: Beyond DOMReady: Ultra High-Performance Javascript

var transformer = function($) {var _transform = function(sel) {

$(sel).toggleClass('robot');}// sets what `transformer` is equal toreturn = {

transform: _transform}

}(jQuery);

Page 22: Beyond DOMReady: Ultra High-Performance Javascript

var transformer = function($) {var _transform = function(sel) {

$(sel).toggleClass('robot');}// sets what `transformer` is equal toreturn = {

transform: _transform}

}(jQuery);

// usagetransformer.transform('.car');

Page 23: Beyond DOMReady: Ultra High-Performance Javascript

var transformer = function($) {var _transform = function(sel) {

$(sel).toggleClass('robot');}// sets what `transformer` is equal toreturn = {

transform: _transform}

}(jQuery);

// usagetransformer.transform('.car');

// result<div class="car robot" />

Page 24: Beyond DOMReady: Ultra High-Performance Javascript

benefits of modular programming

• self contained – includes everything it needs to accomplish it's function.

• namespaced – doesn't dirty the global scope.

Page 25: Beyond DOMReady: Ultra High-Performance Javascript

// you can’t do this… yet

import "transformer.js" as transformer;

Page 26: Beyond DOMReady: Ultra High-Performance Javascript

3rd party loaders

Page 27: Beyond DOMReady: Ultra High-Performance Javascript

3rd party loaders

• LABjs

• HeadJS

• ControlJS

• RequireJS

• Load.js

• YepNope.js

• $script.js

Page 28: Beyond DOMReady: Ultra High-Performance Javascript

3rd party loaders

• LABjs

• HeadJS

• ControlJS

• RequireJS

• Load.js

• YepNope.js

• $script.js

• LazyLoad

• curl.js

• JsDefer

• jquery.defer.js

• BravoJS

• JSLoad

• StealJS

Page 29: Beyond DOMReady: Ultra High-Performance Javascript

3rd party loaders

• LABjs

• HeadJS

• ControlJS

• RequireJS

• Load.js

• YepNope.js

• $script.js

• LazyLoad

• curl.js

• JsDefer

• jquery.defer.js

• BravoJS

• JSLoad

• StealJS …and more

Page 30: Beyond DOMReady: Ultra High-Performance Javascript

I’ll make it easy…

Page 31: Beyond DOMReady: Ultra High-Performance Javascript

I’ll make it easy…

just use RequireJS.

Page 32: Beyond DOMReady: Ultra High-Performance Javascript

I’ll make it easy…

just use RequireJS.

• plugin architecture (text, l10n, css, etc).

• built in support for has.js.

• support for r.js.

• James Burke knows his shit.

• author of the AMD standard.

Page 33: Beyond DOMReady: Ultra High-Performance Javascript

// vanilla js modulevar transformer = function($) {

var _transform = function(sel) {$(sel).toggleClass('robot');

}return = {

transform: _transform}

}(jQuery);

Page 34: Beyond DOMReady: Ultra High-Performance Javascript

// AMD module wraps everything in `define`define(function($) {

var _transform = function(sel) {$(sel).toggleClass('robot');

}return = {

transform: _transform}

}(jQuery));

Page 35: Beyond DOMReady: Ultra High-Performance Javascript

// dependency array is the first parameter of define// dependencies mapped to parameters in the callbackdefine([

'jquery'], function($) {

var _transform = function(sel) {$(sel).toggleClass('robot');

}return = {

transform: _transform}

});

Page 36: Beyond DOMReady: Ultra High-Performance Javascript

// dependency array is the first parameter of define// dependencies mapped to parameters in the callbackdefine([

'jquery','underscore'

], function($, _) {var _transform = function(sel) {

$(sel).toggleClass('robot');}return = {

transform: _transform}

});

Page 37: Beyond DOMReady: Ultra High-Performance Javascript

// usagerequire([

'transformer'], function(transformer) {

transformer.transform('.car');});

Page 38: Beyond DOMReady: Ultra High-Performance Javascript

example website

• common.js – code shared by all pages.

• home/main.js – code unique to the home page.

Page 39: Beyond DOMReady: Ultra High-Performance Javascript

// common.jsdefine([

'jquery','ui/jquery.ui.core','ui/jquery.ui.widget'

], function($) {// setup code for all pages

});

Page 40: Beyond DOMReady: Ultra High-Performance Javascript

// common.jsdefine([

'jquery','ui/jquery.ui.core','ui/jquery.ui.widget'

], function($) {// setup code for all pages

});

// but `jquery.ui.core` and `jquery.ui.widget`// aren’t modules!

Page 41: Beyond DOMReady: Ultra High-Performance Javascript

// common.jsrequirejs.config({

shim: {'ui/jquery.ui.core': {

deps: ['jquery']},'ui/jquery.ui.widget': {

deps: ['ui/jquery.ui.core']}

}});define([

'jquery','ui/jquery.ui.core','ui/jquery.ui.widget'

], function($) {

Page 42: Beyond DOMReady: Ultra High-Performance Javascript

// home/main.jsdefine([

'common','ui/jquery.ui.dialog'

], function($) {$('.modal').dialog();

});

Page 43: Beyond DOMReady: Ultra High-Performance Javascript

// home/main.jsdefine([

'common','ui/jquery.ui.dialog'

], function($) {$('.modal').dialog();

});

// index.html<script src="require.js" data-main="home/main"></script>

Page 44: Beyond DOMReady: Ultra High-Performance Javascript

// home/main.jsdefine([

'common','ui/jquery.ui.dialog'

], function($) {$('.modal').dialog();

});

// index.html<script src="require.js" data-main="<?php echo $template ?>/main"></script>

Page 45: Beyond DOMReady: Ultra High-Performance Javascript

behind the scenes (phase 1)

1. download require.js – 1.

2. download home/main.js – 2.

3. check dependencies.

4. download common.js, ui/jquery.ui.dialog – 4.

5. check dependencies.

6. download jquery, ui/jquery.ui.core, ui/jquery.ui.widget – 7.

7. check dependencies.

Page 46: Beyond DOMReady: Ultra High-Performance Javascript

behind the scenes (phase 2)

1. evaluate jquery, then jquery.ui.core, then jquery.ui.widget.

2. execute the common.js callback.

3. evaluate jquery.ui.dialog.

4. execute the home/main.js callback.

Page 47: Beyond DOMReady: Ultra High-Performance Javascript

modular and maintainable

but crappy performance: 7 requests!

Page 48: Beyond DOMReady: Ultra High-Performance Javascript

make it high-performance

Page 49: Beyond DOMReady: Ultra High-Performance Javascript

introducing r.js

module optimizer.

Page 50: Beyond DOMReady: Ultra High-Performance Javascript

// build.js({

modules: [{

name: "common"},{

name: "home/main"exclude: "common"

}]

})

Page 51: Beyond DOMReady: Ultra High-Performance Javascript

// run it manually // or as part of automated build process java -classpath r.js/lib/rhino/js.jar \

org.mozilla.javascript.tools.shell.Main \r.js/dist/r.js -o build.js

Page 52: Beyond DOMReady: Ultra High-Performance Javascript

// example output

Tracing dependencies for: common

common.js----------------jquery.jsui/jquery.ui.coreui/jquery.ui.widgetcommon.js

Page 53: Beyond DOMReady: Ultra High-Performance Javascript

// example output

Tracing dependencies for: home/main

home/main.js----------------ui/jquery.ui.dialoghome/main.js

Page 54: Beyond DOMReady: Ultra High-Performance Javascript

// example output

Uglifying file: common.jsUglifying file: home/main.js

Page 55: Beyond DOMReady: Ultra High-Performance Javascript

new behind the scenes (phase 1)

1. download require.js – 1.

2. download home/main.js (includes ui/jquery.ui.dialog) – 2.

3. check dependencies.

4. download common.js (includes jquery, ui/jquery.ui.core, ui/jquery.ui.widget) – 3.

5. check dependencies.

Page 56: Beyond DOMReady: Ultra High-Performance Javascript

only 3 requests!

• only 1 request per page after initial page load (require.js and common.js are cached for all pages).

• scripts loads asynchronously (non-blocking) and in parallel.

• all assets optimized (supports uglify or closure compiler).

Page 57: Beyond DOMReady: Ultra High-Performance Javascript

mandatory builds for UI sucks

Page 58: Beyond DOMReady: Ultra High-Performance Javascript

// build.js({

baseUrl: "js-src/", // input folderdir: "js/", // output foldermodules: [

{name: "common"

},{

name: "home/main"exclude: "common"

}]

})

Page 59: Beyond DOMReady: Ultra High-Performance Javascript

// index.html<script src="js/require.js" data-main="<?php echo $_GET['dev'] ? 'js-src/home/main' : 'js/home/main' ?>"></script>

// index.html – production js, 3 requests// index.html?dev - development js, 7 requests

Page 60: Beyond DOMReady: Ultra High-Performance Javascript

even better performance with has.js

feature detection library.

Page 61: Beyond DOMReady: Ultra High-Performance Javascript

define(['has'

], function($) {// add a testvar re = /\bdev\b/;has.add('dev',re.test(window.location.search));// use `has`if (has('dev')) {

console.log('test');}

});

Page 62: Beyond DOMReady: Ultra High-Performance Javascript

define(['has'

], function($) {// add a testvar re = /\bdev\b/;has.add('dev',re.test(window.location.search));// use `has`if (has('dev')) {

console.log('test');}

});

// index.html?dev// "test"

Page 63: Beyond DOMReady: Ultra High-Performance Javascript

// build.js({

baseUrl: "js-src/",dir: "js/",has: {

dev: false},modules: [

…]

})

Page 64: Beyond DOMReady: Ultra High-Performance Javascript

// originalif (has('dev')) {

console.log('test');}

Page 65: Beyond DOMReady: Ultra High-Performance Javascript

// originalif (has('dev')) {

console.log('test');}

// after r.js pre-processingif (false) {

console.log('test');}

Page 66: Beyond DOMReady: Ultra High-Performance Javascript

// originalif (has('dev')) {

console.log('test');}

// after r.js pre-processingif (false) {

console.log('test');}

// after uglify post-processing// nothing – uglify strips dead code branches

Page 67: Beyond DOMReady: Ultra High-Performance Javascript

has.add('ie7-support', true);if (has('ie7-support') {

// some godawful hack to fix something in ie7}

Page 68: Beyond DOMReady: Ultra High-Performance Javascript

make it ultra high-performance

Page 69: Beyond DOMReady: Ultra High-Performance Javascript

even better performance with almond

intended for single page apps or mobile where request latency is much worse than desktop.

• require.js = 16.5k minified (6k gzipped)

• almond.js = 2.3k minified (~1k gzipped)

Page 70: Beyond DOMReady: Ultra High-Performance Javascript

only 1 request… ever.

• shaves 14k of boilerplate.

Page 71: Beyond DOMReady: Ultra High-Performance Javascript

1st step to ultra high performance

use modular programming.

• combine with require.js for asynchronous / parallel loading.

• automatic concatenation, optimization.

• for ultra performance use almond.js.

Page 72: Beyond DOMReady: Ultra High-Performance Javascript

anyone not use jquery?

“Study shows half of all websites use jQuery”

– August, 2012

Page 73: Beyond DOMReady: Ultra High-Performance Javascript

// example of a jquery plugin used with a moduledefine([

'jquery','jquery.craftyslide'

], function($) {$('#slideshow').craftyslide();

});

Page 74: Beyond DOMReady: Ultra High-Performance Javascript

// closer look at `craftyslide.js`$.fn.craftyslide = function (options) {

function paginate() {…

}function captions() {

…}function manual() {

…}

paginate(); captions(); manual();}

Page 75: Beyond DOMReady: Ultra High-Performance Javascript

problem with jquery plugins

they’re a black box.

• not easily extendable.

• not easily testable.

Page 76: Beyond DOMReady: Ultra High-Performance Javascript

problem with jquery plugins

they’re a black box.

• not easily extendable.

• not easily testable.

jquery ui set out to solve this with…

Page 77: Beyond DOMReady: Ultra High-Performance Javascript

uiwidgets

Page 78: Beyond DOMReady: Ultra High-Performance Javascript

oh noes! not jquery ui

bloated piece of crap (210k omg!)

• jquery ui is modular – use just the bits you need.

• ui core + ui widget + effects core (16k minified or ~6k gzipped).

Page 79: Beyond DOMReady: Ultra High-Performance Javascript

ui widgets

the two things plugins suck at, widgets do really well:

• they're fully extendable.

Page 80: Beyond DOMReady: Ultra High-Performance Javascript

simple javascript inheritence

25 lines of javascript sexiness:

• constructors.

• object-oriented inheritence.

• access to overridden (super) methods.

Page 81: Beyond DOMReady: Ultra High-Performance Javascript

simple javascript inheritence

25 lines of javascript sexiness:

• constructors.

• object-oriented inheritence.

• access to overridden (super) methods.

also the foundation of ui widget extensibility.

Page 82: Beyond DOMReady: Ultra High-Performance Javascript

// example widget$.widget('ui.transformer', {

options: {…

},_create: function() {

…}

);

Page 83: Beyond DOMReady: Ultra High-Performance Javascript

// example widget$.widget('ui.transformer', {

options: {…

},_create: function() {

…}

);

// extending it$.widget('ui.autobot', $.ui.transformer, {

// extend anything or everything});

Page 84: Beyond DOMReady: Ultra High-Performance Javascript

not-so simple javascript inheritence

everything from simple javascript inheritence, plus:

• namespaces.

• public and private methods.

• getters/setters.

• disable/enable.

Page 85: Beyond DOMReady: Ultra High-Performance Javascript

ui widgets

the two things plugins suck at, widgets do really well:

• they're fully extendable.

• they're tuned for testing.

Page 86: Beyond DOMReady: Ultra High-Performance Javascript

// if `craftyslide` were a widget$.widget('ui.craftyslide', {

_create: function() {…this._paginate();this._captions();this._manual();

},_paginate: function(){ … },_captions: function(){ … },_manual: function(){ … }

);

Page 87: Beyond DOMReady: Ultra High-Performance Javascript

// adding triggers as hooks for testing$.widget('ui.craftyslide', {

…_paginate: function(){

this._trigger('beforePaginate');…this._trigger('afterPaginate');

},…

);

Page 88: Beyond DOMReady: Ultra High-Performance Javascript

// in your unit testfunction beforePaginate() {

// test conditions}function afterPaginate() {

// test conditions}$('#slideshow').craftyslide({

beforePaginate: beforePaginate, afterPaginate: afterPaginate

});

Page 89: Beyond DOMReady: Ultra High-Performance Javascript

// plugin using `.on()`function manual() {

…$pagination.on('click', function (e) {

… });

}

Page 90: Beyond DOMReady: Ultra High-Performance Javascript

// plugin using `.on()`function manual() {

…$pagination.on('click', function (e) {

… });

}

// widget using `._on()`manual: function() {

this._on($pagination, { click: '_click' }}

Page 91: Beyond DOMReady: Ultra High-Performance Javascript

// `._on()` remembers all event bindings_on: function( element, handlers ) {

…this.bindings = this.bindings.add( element );

},

Page 92: Beyond DOMReady: Ultra High-Performance Javascript

// `._on()` remembers all event bindings_on: function( element, handlers ) {

…this.bindings = this.bindings.add( element );

},

// `.remove()` triggers a `remove` eventthis._on({ remove: "destroy" });

Page 93: Beyond DOMReady: Ultra High-Performance Javascript

// `._on()` remembers all event bindings_on: function( element, handlers ) {

…this.bindings = this.bindings.add( element );

},

// `.remove()` triggers a `remove` eventthis._on({ remove: "destroy" });

// `.destroy()` cleans up all bindings// leaving the DOM pristinedestroy: function() {

…this.bindings.unbind( this.eventNamespace );

}

Page 94: Beyond DOMReady: Ultra High-Performance Javascript

// setup widget$('#slideshow').craftyslide();

// run tests…

// teardown// calls `.destroy()` // which automatically unbinds all bindings$('#slideshow').remove();

Page 95: Beyond DOMReady: Ultra High-Performance Javascript

high-performance from code re-use

Page 96: Beyond DOMReady: Ultra High-Performance Javascript

define(['jquery','ui/jquery.ui.core','ui/jquery.ui.widget','ui/jquery.ui.craftyslide'

], function($) {$.widget('ui.craftyslide', $.ui.craftyslide, {

_manual: function() {// extend to do whatever I want

}});

});

Page 97: Beyond DOMReady: Ultra High-Performance Javascript

2nd step to ultra high performance

use object-oriented widgets as code building blocks.

• inheritance promotes code re-use, smaller codebase.

• built on an architecture that promotes testability.

Page 98: Beyond DOMReady: Ultra High-Performance Javascript

made possible via

• fast file loading.

• small file sizes.

• avoiding DOM bottlenecks.

Page 99: Beyond DOMReady: Ultra High-Performance Javascript

avoiding DOM bottlenecks

Page 100: Beyond DOMReady: Ultra High-Performance Javascript

eventdelegation

Page 101: Beyond DOMReady: Ultra High-Performance Javascript

<ul id="transformers"><li><a>Bumblebee</a></li><li><a>Ratchet</a></li><li><a>Ironhide</a></li>

</ul>

// typical event binding$('#transformers a').on('click', function() {

// do something});

Page 102: Beyond DOMReady: Ultra High-Performance Javascript

<ul id="transformers"><li><a>Bumblebee</a></li><li><a>Ratchet</a></li><li><a>Ironhide</a></li>

</ul>

// typical event binding$('#transformers a').on('click', function() {

// do something});

// event bubbling allows us to do this$('#transformers').on('click', function() {

// do something});

Page 103: Beyond DOMReady: Ultra High-Performance Javascript

// event delegation is similar$('#transformers').on('click', 'a', function() {

// do something});

Page 104: Beyond DOMReady: Ultra High-Performance Javascript

// event delegation is similar$('#transformers').on('click', 'a', function() {

// do something});

// but allows us to do this$(document).on('click', '#transformers a', function()

// do something});

Page 105: Beyond DOMReady: Ultra High-Performance Javascript

why does that kick ass?

• more performant – less memory, faster to bind/unbind.

• less maintenance – you can add/remove <ul id="transformers"> at any point in time and don't need to re-attach the event listener.

• faster – you can bind the event listener to document as soon as the javascript has loaded, you don't need to wait for domready.

Page 106: Beyond DOMReady: Ultra High-Performance Javascript

how does this work with widgets?

it doesnt – widget's pitfall is they are a DOM bottleneck.

Page 107: Beyond DOMReady: Ultra High-Performance Javascript

// example `lightbox` widget$('#gallery a').lightbox();

// widget depends on `this.element`$.widget('ui.lightbox', {

_create: function() {this._on(this.element, { click: 'show' });

}});

Page 108: Beyond DOMReady: Ultra High-Performance Javascript

two workarounds

• one for legacy widgets.

• better approach for new widgets.

Page 109: Beyond DOMReady: Ultra High-Performance Javascript

// legacy widgets$(document).on('click', '#gallery a', function() {

$(this).lightbox().lightbox('show');

});

Page 110: Beyond DOMReady: Ultra High-Performance Javascript

// new widgets$.widget('ui.lightbox', {

_create: function() {var sel = this.options.selector;var handler = {};handler['click ' + sel] = 'show’;this._on(handler);

}});

Page 111: Beyond DOMReady: Ultra High-Performance Javascript

// new widgets$.widget('ui.lightbox', {

_create: function() {var sel = this.options.selector;var handler = {};handler['click ' + sel] = 'show’;this._on(handler);

}});

// always instantiate on the document$(document).lightbox({

selector: '#gallery a' });

Page 112: Beyond DOMReady: Ultra High-Performance Javascript

3rd step to ultra high performance

delegate anything and everything you can.

• will add interaction to elements that are lazy-loaded, inserted via ajax after page load, etc.

• allows for interaction before domready!

Page 113: Beyond DOMReady: Ultra High-Performance Javascript

delegation isn’t a cure all

delegation works great when the widget doesn't need to know about the user up until the user interacts with it.

but what about widgets that need to affect the DOM on instantiation…

Page 114: Beyond DOMReady: Ultra High-Performance Javascript

how we’ve done this previously

• document.load – the 80's of the internet.

• document.DOMContentLoaded – the new load event!

Page 115: Beyond DOMReady: Ultra High-Performance Javascript

domready considered an anti-pattern

“the short story is that we don't want to wait for DOMContentReady (or worse the load event) since it leads to bad user experience. the UI is not responsive until all the DOM has been loaded from the network. so the preferred way is to use inline scripts as soon as possible”

– Google Closure team

Page 116: Beyond DOMReady: Ultra High-Performance Javascript

<ul id="transformers"><li><a>Bumblebee</a></li><li><a>Ratchet</a></li><li><a>Ironside</a></li>

</ul><script>

$('#transformers').slideshow();</script>

Page 117: Beyond DOMReady: Ultra High-Performance Javascript

oh no you didn’t

a problem with our modular approach:

• nothing is exposed to the global scope – you can't use modules from the DOM.

Page 118: Beyond DOMReady: Ultra High-Performance Javascript

mediator pattern to the rescue

a central point of control that modules communicate through – instead of directly with each other.

Page 119: Beyond DOMReady: Ultra High-Performance Javascript

pubsub

Page 120: Beyond DOMReady: Ultra High-Performance Javascript

central point of control

• publish

• subscribe

• unsubscribe

Page 121: Beyond DOMReady: Ultra High-Performance Javascript

it’s so easy

• publish = $.trigger

• subscribe = $.on

• unsubscribe = $.off

Page 122: Beyond DOMReady: Ultra High-Performance Javascript

// in codevar proxy = $({});window.publish = function() {

proxy.trigger.apply(proxy, arguments);}window.subscribe = function() {

proxy.on.apply(proxy, arguments);}window.unsubcribe = function() {

proxy.off.apply(proxy, arguments);}

Page 123: Beyond DOMReady: Ultra High-Performance Javascript

<ul id="transformers"><li><a>Bumblebee</a></li><li><a>Ratchet</a></li><li><a>Ironside</a></li>

</ul><script>

publish('load.transformers');</script>

Page 124: Beyond DOMReady: Ultra High-Performance Javascript

define(['main'

], function() {subscribe('load.transformers', function() {

$('#transformers').slideshow();});

});

Page 125: Beyond DOMReady: Ultra High-Performance Javascript

oh no you didn't

two problems with our modular approach:

• nothing is exposed to the global scope – you can't use modules from the DOM.

• if the JS is loaded asynchronously you don't know that it's available when the browser is parsing the HTML.

Page 126: Beyond DOMReady: Ultra High-Performance Javascript

<head>// blocking, should be tiny (1k) or inlined!<script src="bootstrap.js"></script>// asynchronous non-blocking<script src="require.js" data-main="home/main"></script>

Page 127: Beyond DOMReady: Ultra High-Performance Javascript

// bootstrap.js// needs to be some global object// but we can clean it up afterwardsdocument.queue = [];window.publish = function() {

document.queue.push(arguments);}

Page 128: Beyond DOMReady: Ultra High-Performance Javascript

<script>publish('load.transformers');

</script>

// document.queue = [['load.transformers']]

Page 129: Beyond DOMReady: Ultra High-Performance Javascript

// main.jsdefine([

'jquery'], function($) {

var proxy = $({});window.publish = function() {

proxy.trigger.apply(proxy, arguments);}window.unsubcribe = function() {

proxy.off.apply(proxy, arguments);}…

Page 130: Beyond DOMReady: Ultra High-Performance Javascript

window.subscribe = function(event) {proxy.on.apply(proxy, arguments);

});

Page 131: Beyond DOMReady: Ultra High-Performance Javascript

window.subscribe = function(event) {proxy.on.apply(proxy, arguments);$(document.queue).each(function(index) {

if (this[0] === event) {proxy.trigger.apply(proxy, this);document.queue.splice(index, 1);return false;

}});

});

Page 132: Beyond DOMReady: Ultra High-Performance Javascript

ultra high-performance achieved!

Page 133: Beyond DOMReady: Ultra High-Performance Javascript

ultra high-performance achieved!

1. use modular programming.

2. use object-oriented widgets as code building blocks.

3. delegate anything and everything you can.

4. use pubsub for everything else.

Page 134: Beyond DOMReady: Ultra High-Performance Javascript

onesec

Page 135: Beyond DOMReady: Ultra High-Performance Javascript

about me

Page 136: Beyond DOMReady: Ultra High-Performance Javascript

about me

• I like Land Cruisers.

• lived in Costa Rica for 10 years (there is no excuse for how I speak).

• UI dev lead / mobile developer at Backcountry.

Page 137: Beyond DOMReady: Ultra High-Performance Javascript
Page 138: Beyond DOMReady: Ultra High-Performance Javascript
Page 139: Beyond DOMReady: Ultra High-Performance Javascript

questionspreguntas?