SlideShare une entreprise Scribd logo
1  sur  139
this is not a TEDTALK
not high-performance javascript
ultra high-performance javascript
what is ultra high-performance?
made possible via

• fast file loading.
• small file sizes.
• avoiding DOM bottlenecks.
what high-performance looks like
hint: in general it looks awful
high-performance != maintainability

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

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

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

• separate code into modules, each of which
  accomplishes a single function.
• expose the module through an interface.
modularprogramming
module pattern

module consists of 3 parts:
module pattern

module consists of 3 parts:


1. function (what it does)
var _transform = function(sel) {
        $(sel).toggleClass('robot');
}
// wrapped in a self-executing function
var transformer = function() {
        var _transform = function(sel) {
                 $(sel).toggleClass('robot');
        }
}();
module pattern

module consists of 3 parts:


1. function (what it does)
2. dependencies (what it needs)
var transformer = function($) {
        var _transform = function(sel) {
                $(sel).toggleClass('robot');
        }
}(jQuery);
module pattern

module consists of 3 parts:


1. function (what it does)
2. dependencies (what it needs)
3. interface (what it returns)
var transformer = function($) {
        var _transform = function(sel) {
                 $(sel).toggleClass('robot');
        }
        // sets what `transformer` is equal to
        return = {
                 transform: _transform
        }
}(jQuery);
var transformer = function($) {
        var _transform = function(sel) {
                 $(sel).toggleClass('robot');
        }
        // sets what `transformer` is equal to
        return = {
                 transform: _transform
        }
}(jQuery);

// usage
transformer.transform('.car');
var transformer = function($) {
        var _transform = function(sel) {
                 $(sel).toggleClass('robot');
        }
        // sets what `transformer` is equal to
        return = {
                 transform: _transform
        }
}(jQuery);

// usage
transformer.transform('.car');

// result
<div class="car robot" />
benefits of modular programming

• self contained – includes everything it needs
  to accomplish it's function.
• namespaced – doesn't dirty the global
  scope.
// you can’t do this… yet
import "transformer.js" as transformer;
3rd party loaders
3rd party loaders

• LABjs
• HeadJS
• ControlJS
• RequireJS
• Load.js
• YepNope.js
• $script.js
3rd party loaders

• LABjs             • LazyLoad
• HeadJS            • curl.js
• ControlJS         • JsDefer
• RequireJS         • jquery.defer.js
• Load.js           • BravoJS
• YepNope.js        • JSLoad
• $script.js        • StealJS
3rd party loaders

• LABjs             • LazyLoad
• HeadJS            • curl.js
• ControlJS         • JsDefer
• RequireJS         • jquery.defer.js
• Load.js           • BravoJS
• YepNope.js        • JSLoad
• $script.js        • StealJS …and
                      more
I’ll make it easy…
I’ll make it easy…

just use RequireJS.
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.
// vanilla js module
var transformer = function($) {
          var _transform = function(sel) {
                   $(sel).toggleClass('robot');
          }
          return = {
                   transform: _transform
          }
}(jQuery);
// AMD module wraps everything in `define`
define(function($) {
        var _transform = function(sel) {
                 $(sel).toggleClass('robot');
        }
        return = {
                 transform: _transform
        }
}(jQuery));
// dependency array is the first parameter of define
// dependencies mapped to parameters in the callback
define([
          'jquery'
], function($) {
          var _transform = function(sel) {
                   $(sel).toggleClass('robot');
          }
          return = {
                   transform: _transform
          }
});
// dependency array is the first parameter of define
// dependencies mapped to parameters in the callback
define([
          'jquery',
          'underscore'
], function($, _) {
          var _transform = function(sel) {
                    $(sel).toggleClass('robot');
          }
          return = {
                    transform: _transform
          }
});
// usage
require([
          'transformer'
], function(transformer) {
          transformer.transform('.car');
});
example website

• common.js – code shared by all pages.
• home/main.js – code unique to the home
  page.
// common.js
define([
          'jquery',
          'ui/jquery.ui.core',
          'ui/jquery.ui.widget'
], function($) {
          // setup code for all pages
});
// common.js
define([
          '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!
// common.js
requirejs.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($) {
// home/main.js
define([
          'common',
          'ui/jquery.ui.dialog'
], function($) {
          $('.modal').dialog();
});
// home/main.js
define([
          'common',
          'ui/jquery.ui.dialog'
], function($) {
          $('.modal').dialog();
});

// index.html
<script src="require.js" data-main="home/main"></script>
// home/main.js
define([
          'common',
          'ui/jquery.ui.dialog'
], function($) {
          $('.modal').dialog();
});

// index.html
<script src="require.js" data-main="<?php echo $template
?>/main"></script>
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.
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.
modular and maintainable

but crappy performance: 7 requests!
make it high-performance
introducing r.js

module optimizer.
// build.js
({
          modules: [
                 {
                       name: "common"
                 },
                 {
                       name: "home/main"
                       exclude: "common"
                 }
        ]
})
// 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
// example output

Tracing dependencies for: common

common.js
----------------
jquery.js
ui/jquery.ui.core
ui/jquery.ui.widget
common.js
// example output

Tracing dependencies for: home/main

home/main.js
----------------
ui/jquery.ui.dialog
home/main.js
// example output

Uglifying file: common.js
Uglifying file: home/main.js
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.
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).
mandatory builds for UI sucks
// build.js
({
          baseUrl: "js-src/", // input folder
          dir: "js/", // output folder
          modules: [
                     {
                              name: "common"
                     },
                     {
                              name: "home/main"
                              exclude: "common"
                     }
          ]
})
// 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
even better performance with has.js

feature detection library.
define([
          'has'
], function($) {
          // add a test
          var re = /bdevb/;
          has.add('dev',re.test(window.location.search));
          // use `has`
          if (has('dev')) {
                    console.log('test');
          }
});
define([
          'has'
], function($) {
          // add a test
          var re = /bdevb/;
          has.add('dev',re.test(window.location.search));
          // use `has`
          if (has('dev')) {
                    console.log('test');
          }
});

// index.html?dev
// "test"
// build.js
({
          baseUrl: "js-src/",
          dir: "js/",
          has: {
                     dev: false
          },
          modules: [
                     …
          ]
})
// original
if (has('dev')) {
          console.log('test');
}
// original
if (has('dev')) {
          console.log('test');
}

// after r.js pre-processing
if (false) {
           console.log('test');
}
// original
if (has('dev')) {
          console.log('test');
}

// after r.js pre-processing
if (false) {
           console.log('test');
}

// after uglify post-processing
// nothing – uglify strips dead code branches
has.add('ie7-support', true);
if (has('ie7-support') {
          // some godawful hack to fix something in ie7
}
make it ultra high-performance
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)
only 1 request… ever.

• shaves 14k of boilerplate.
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.
anyone not use jquery?

“Study shows half of all websites use jQuery”
                                  – August, 2012
// example of a jquery plugin used with a module
define([
          'jquery',
          'jquery.craftyslide'
], function($) {
          $('#slideshow').craftyslide();
});
// closer look at `craftyslide.js`
$.fn.craftyslide = function (options) {
         function paginate() {
                   …
         }
         function captions() {
                   …
         }
         function manual() {
                   …
         }

        paginate(); captions(); manual();
}
problem with jquery plugins

they’re a black box.


• not easily extendable.
• not easily testable.
problem with jquery plugins

they’re a black box.


• not easily extendable.
• not easily testable.


jquery ui set out to solve this with…
uiwidgets
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).
ui widgets

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


• they're fully extendable.
simple javascript inheritence

25 lines of javascript sexiness:


• constructors.
• object-oriented inheritence.
• access to overridden (super) methods.
simple javascript inheritence

25 lines of javascript sexiness:


• constructors.
• object-oriented inheritence.
• access to overridden (super) methods.


also the foundation of ui widget extensibility.
// example widget
$.widget('ui.transformer', {
        options: {
                 …
        },
        _create: function() {
                 …
        }
);
// example widget
$.widget('ui.transformer', {
        options: {
                 …
        },
        _create: function() {
                 …
        }
);

// extending it
$.widget('ui.autobot', $.ui.transformer, {
         // extend anything or everything
});
not-so simple javascript inheritence

everything from simple javascript inheritence,
plus:


• namespaces.
• public and private methods.
• getters/setters.
• disable/enable.
ui widgets

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


• they're fully extendable.
• they're tuned for testing.
// if `craftyslide` were a widget
$.widget('ui.craftyslide', {
           _create: function() {
                    …
                    this._paginate();
                    this._captions();
                    this._manual();
           },
           _paginate: function(){ … },
           _captions: function(){ … },
           _manual: function(){ … }
);
// adding triggers as hooks for testing
$.widget('ui.craftyslide', {
         …
         _paginate: function(){
                  this._trigger('beforePaginate');
                  …
                  this._trigger('afterPaginate');
         },
         …
);
// in your unit test
function beforePaginate() {
         // test conditions
}
function afterPaginate() {
         // test conditions
}
$('#slideshow').craftyslide({
         beforePaginate: beforePaginate,
         afterPaginate: afterPaginate
});
// plugin using `.on()`
function manual() {
         …
         $pagination.on('click', function (e) {
                  …
         });
}
// plugin using `.on()`
function manual() {
         …
         $pagination.on('click', function (e) {
                  …
         });
}

// widget using `._on()`
manual: function() {
         this._on($pagination, { click: '_click' }
}
// `._on()` remembers all event bindings
_on: function( element, handlers ) {
         …
         this.bindings = this.bindings.add( element );
},
// `._on()` remembers all event bindings
_on: function( element, handlers ) {
         …
         this.bindings = this.bindings.add( element );
},

// `.remove()` triggers a `remove` event
this._on({ remove: "destroy" });
// `._on()` remembers all event bindings
_on: function( element, handlers ) {
         …
         this.bindings = this.bindings.add( element );
},

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

// `.destroy()` cleans up all bindings
// leaving the DOM pristine
destroy: function() {
          …
          this.bindings.unbind( this.eventNamespace );
}
// setup widget
$('#slideshow').craftyslide();

// run tests
…

// teardown
// calls `.destroy()`
// which automatically unbinds all bindings
$('#slideshow').remove();
high-performance from code re-use
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
                    }
          });
});
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.
made possible via

• fast file loading.
• small file sizes.
• avoiding DOM bottlenecks.
avoiding DOM bottlenecks
eventdelegation
<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
});
<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
});
// event delegation is similar
$('#transformers').on('click', 'a', function() {
         // do something
});
// 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
});
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.
how does this work with widgets?

it doesnt – widget's pitfall is they are a DOM
bottleneck.
// example `lightbox` widget
$('#gallery a').lightbox();

// widget depends on `this.element`
$.widget('ui.lightbox', {
         _create: function() {
                  this._on(this.element, { click: 'show' });
         }
});
two workarounds

• one for legacy widgets.
• better approach for new widgets.
// legacy widgets
$(document).on('click', '#gallery a', function() {
         $(this)
                 .lightbox()
                 .lightbox('show');
});
// new widgets
$.widget('ui.lightbox', {
        _create: function() {
                  var sel = this.options.selector;
                  var handler = {};
                  handler['click ' + sel] = 'show’;
                  this._on(handler);
        }
});
// 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'
});
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!
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…
how we’ve done this previously

• document.load – the 80's of the internet.
• document.DOMContentLoaded – the new
  load event!
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
<ul id="transformers">
         <li><a>Bumblebee</a></li>
         <li><a>Ratchet</a></li>
         <li><a>Ironside</a></li>
</ul>
<script>
         $('#transformers').slideshow();
</script>
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.
mediator pattern to the rescue

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

• publish
• subscribe
• unsubscribe
it’s so easy

• publish = $.trigger
• subscribe = $.on
• unsubscribe = $.off
// in code
var 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);
}
<ul id="transformers">
         <li><a>Bumblebee</a></li>
         <li><a>Ratchet</a></li>
         <li><a>Ironside</a></li>
</ul>
<script>
         publish('load.transformers');
</script>
define([
          'main'
], function() {
          subscribe('load.transformers', function() {
                  $('#transformers').slideshow();
          });
});
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.
<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>
// bootstrap.js
// needs to be some global object
// but we can clean it up afterwards
document.queue = [];
window.publish = function() {
         document.queue.push(arguments);
}
<script>
         publish('load.transformers');
</script>

// document.queue = [['load.transformers']]
// main.js
define([
          'jquery'
], function($) {
          var proxy = $({});
          window.publish = function() {
                   proxy.trigger.apply(proxy, arguments);
          }
          window.unsubcribe = function() {
                   proxy.off.apply(proxy, arguments);
          }
          …
window.subscribe = function(event) {
       proxy.on.apply(proxy, arguments);
});
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;
               }
       });
});
ultra high-performance achieved!
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.
onesec
about me
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.
questionspreguntas?

Contenu connexe

Tendances

Mulberry: A Mobile App Development Toolkit
Mulberry: A Mobile App Development ToolkitMulberry: A Mobile App Development Toolkit
Mulberry: A Mobile App Development ToolkitRebecca Murphey
 
AngularJS Services
AngularJS ServicesAngularJS Services
AngularJS ServicesEyal Vardi
 
AngularJS Directives
AngularJS DirectivesAngularJS Directives
AngularJS DirectivesEyal Vardi
 
AngularJS Compile Process
AngularJS Compile ProcessAngularJS Compile Process
AngularJS Compile ProcessEyal Vardi
 
Using Objects to Organize your jQuery Code
Using Objects to Organize your jQuery CodeUsing Objects to Organize your jQuery Code
Using Objects to Organize your jQuery CodeRebecca Murphey
 
Building Large jQuery Applications
Building Large jQuery ApplicationsBuilding Large jQuery Applications
Building Large jQuery ApplicationsRebecca Murphey
 
ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperGary Hockin
 
Drupal Development (Part 2)
Drupal Development (Part 2)Drupal Development (Part 2)
Drupal Development (Part 2)Jeff Eaton
 
Overlays, Accordions & Tabs, Oh My
Overlays, Accordions & Tabs, Oh MyOverlays, Accordions & Tabs, Oh My
Overlays, Accordions & Tabs, Oh MySteve McMahon
 
WordPress plugin #3
WordPress plugin #3WordPress plugin #3
WordPress plugin #3giwoolee
 
AngularJS - $http & $resource Services
AngularJS - $http & $resource ServicesAngularJS - $http & $resource Services
AngularJS - $http & $resource ServicesEyal Vardi
 
Template syntax in Angular 2.0
Template syntax in Angular 2.0Template syntax in Angular 2.0
Template syntax in Angular 2.0Eyal Vardi
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
How to Build SPA with Vue Router 2.0
How to Build SPA with Vue Router 2.0How to Build SPA with Vue Router 2.0
How to Build SPA with Vue Router 2.0Takuya Tejima
 
[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법Jeado Ko
 

Tendances (20)

Your Entity, Your Code
Your Entity, Your CodeYour Entity, Your Code
Your Entity, Your Code
 
Mulberry: A Mobile App Development Toolkit
Mulberry: A Mobile App Development ToolkitMulberry: A Mobile App Development Toolkit
Mulberry: A Mobile App Development Toolkit
 
AngularJS Services
AngularJS ServicesAngularJS Services
AngularJS Services
 
AngularJS Directives
AngularJS DirectivesAngularJS Directives
AngularJS Directives
 
UI-Router
UI-RouterUI-Router
UI-Router
 
AngularJS Compile Process
AngularJS Compile ProcessAngularJS Compile Process
AngularJS Compile Process
 
Using Objects to Organize your jQuery Code
Using Objects to Organize your jQuery CodeUsing Objects to Organize your jQuery Code
Using Objects to Organize your jQuery Code
 
Building Large jQuery Applications
Building Large jQuery ApplicationsBuilding Large jQuery Applications
Building Large jQuery Applications
 
ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 Developer
 
Dojo Confessions
Dojo ConfessionsDojo Confessions
Dojo Confessions
 
Drupal Development (Part 2)
Drupal Development (Part 2)Drupal Development (Part 2)
Drupal Development (Part 2)
 
Overlays, Accordions & Tabs, Oh My
Overlays, Accordions & Tabs, Oh MyOverlays, Accordions & Tabs, Oh My
Overlays, Accordions & Tabs, Oh My
 
The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
WordPress plugin #3
WordPress plugin #3WordPress plugin #3
WordPress plugin #3
 
AngularJS - $http & $resource Services
AngularJS - $http & $resource ServicesAngularJS - $http & $resource Services
AngularJS - $http & $resource Services
 
DrupalCon jQuery
DrupalCon jQueryDrupalCon jQuery
DrupalCon jQuery
 
Template syntax in Angular 2.0
Template syntax in Angular 2.0Template syntax in Angular 2.0
Template syntax in Angular 2.0
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
How to Build SPA with Vue Router 2.0
How to Build SPA with Vue Router 2.0How to Build SPA with Vue Router 2.0
How to Build SPA with Vue Router 2.0
 
[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법
 

Similaire à Beyond DOMReady: Ultra High-Performance Javascript

Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJSAaronius
 
Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenerytoddbr
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js frameworkBen Lin
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)arcware
 
jQuery and Rails: Best Friends Forever
jQuery and Rails: Best Friends ForeverjQuery and Rails: Best Friends Forever
jQuery and Rails: Best Friends Foreverstephskardal
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...Fabio Franzini
 
Javascript ui for rest services
Javascript ui for rest servicesJavascript ui for rest services
Javascript ui for rest servicesIoan Eugen Stan
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
Build Web Apps using Node.js
Build Web Apps using Node.jsBuild Web Apps using Node.js
Build Web Apps using Node.jsdavidchubbs
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
Javascript Frameworks for Joomla
Javascript Frameworks for JoomlaJavascript Frameworks for Joomla
Javascript Frameworks for JoomlaLuke Summerfield
 
Module, AMD, RequireJS
Module, AMD, RequireJSModule, AMD, RequireJS
Module, AMD, RequireJS偉格 高
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For ManagersAgileThought
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing UpDavid Padbury
 
Zend Framework 2 - Basic Components
Zend Framework 2  - Basic ComponentsZend Framework 2  - Basic Components
Zend Framework 2 - Basic ComponentsMateusz Tymek
 
Voorhoede - Front-end architecture
Voorhoede - Front-end architectureVoorhoede - Front-end architecture
Voorhoede - Front-end architectureJasper Moelker
 
Writing testable js [by Ted Piotrowski]
Writing testable js [by Ted Piotrowski]Writing testable js [by Ted Piotrowski]
Writing testable js [by Ted Piotrowski]JavaScript Meetup HCMC
 
Webpack: your final module bundler
Webpack: your final module bundlerWebpack: your final module bundler
Webpack: your final module bundlerAndrea Giannantonio
 

Similaire à Beyond DOMReady: Ultra High-Performance Javascript (20)

Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJS
 
Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenery
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
 
jQuery and Rails: Best Friends Forever
jQuery and Rails: Best Friends ForeverjQuery and Rails: Best Friends Forever
jQuery and Rails: Best Friends Forever
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
Javascript ui for rest services
Javascript ui for rest servicesJavascript ui for rest services
Javascript ui for rest services
 
RequireJS
RequireJSRequireJS
RequireJS
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
Build Web Apps using Node.js
Build Web Apps using Node.jsBuild Web Apps using Node.js
Build Web Apps using Node.js
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Javascript Frameworks for Joomla
Javascript Frameworks for JoomlaJavascript Frameworks for Joomla
Javascript Frameworks for Joomla
 
Module, AMD, RequireJS
Module, AMD, RequireJSModule, AMD, RequireJS
Module, AMD, RequireJS
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For Managers
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
Zend Framework 2 - Basic Components
Zend Framework 2  - Basic ComponentsZend Framework 2  - Basic Components
Zend Framework 2 - Basic Components
 
Voorhoede - Front-end architecture
Voorhoede - Front-end architectureVoorhoede - Front-end architecture
Voorhoede - Front-end architecture
 
Writing testable js [by Ted Piotrowski]
Writing testable js [by Ted Piotrowski]Writing testable js [by Ted Piotrowski]
Writing testable js [by Ted Piotrowski]
 
Webpack: your final module bundler
Webpack: your final module bundlerWebpack: your final module bundler
Webpack: your final module bundler
 

Dernier

The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...panagenda
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditSkynet Technologies
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Scott Andery
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 

Dernier (20)

The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance Audit
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 

Beyond DOMReady: Ultra High-Performance Javascript

  • 1.
  • 2. this is not a TEDTALK
  • 5. what is ultra high-performance?
  • 6. made possible via • fast file loading. • small file sizes. • avoiding DOM bottlenecks.
  • 8. hint: in general it looks awful
  • 9. high-performance != maintainability the elements of high-performance are usually at odds with best practices in maintainability…
  • 10. an approach start with maintainability, and achieve high- performance by building it in via automated processes.
  • 11. large-scale JS to write maintainable code, look at the patterns used by other large-scale JS frameworks:
  • 12. large-scale JS • separate code into modules, each of which accomplishes a single function. • expose the module through an interface.
  • 15. module pattern module consists of 3 parts: 1. function (what it does)
  • 16. var _transform = function(sel) { $(sel).toggleClass('robot'); }
  • 17. // wrapped in a self-executing function var transformer = function() { var _transform = function(sel) { $(sel).toggleClass('robot'); } }();
  • 18. module pattern module consists of 3 parts: 1. function (what it does) 2. dependencies (what it needs)
  • 19. var transformer = function($) { var _transform = function(sel) { $(sel).toggleClass('robot'); } }(jQuery);
  • 20. module pattern module consists of 3 parts: 1. function (what it does) 2. dependencies (what it needs) 3. interface (what it returns)
  • 21. var transformer = function($) { var _transform = function(sel) { $(sel).toggleClass('robot'); } // sets what `transformer` is equal to return = { transform: _transform } }(jQuery);
  • 22. var transformer = function($) { var _transform = function(sel) { $(sel).toggleClass('robot'); } // sets what `transformer` is equal to return = { transform: _transform } }(jQuery); // usage transformer.transform('.car');
  • 23. var transformer = function($) { var _transform = function(sel) { $(sel).toggleClass('robot'); } // sets what `transformer` is equal to return = { transform: _transform } }(jQuery); // usage transformer.transform('.car'); // result <div class="car robot" />
  • 24. benefits of modular programming • self contained – includes everything it needs to accomplish it's function. • namespaced – doesn't dirty the global scope.
  • 25. // you can’t do this… yet import "transformer.js" as transformer;
  • 27. 3rd party loaders • LABjs • HeadJS • ControlJS • RequireJS • Load.js • YepNope.js • $script.js
  • 28. 3rd party loaders • LABjs • LazyLoad • HeadJS • curl.js • ControlJS • JsDefer • RequireJS • jquery.defer.js • Load.js • BravoJS • YepNope.js • JSLoad • $script.js • StealJS
  • 29. 3rd party loaders • LABjs • LazyLoad • HeadJS • curl.js • ControlJS • JsDefer • RequireJS • jquery.defer.js • Load.js • BravoJS • YepNope.js • JSLoad • $script.js • StealJS …and more
  • 30. I’ll make it easy…
  • 31. I’ll make it easy… just use RequireJS.
  • 32. 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.
  • 33. // vanilla js module var transformer = function($) { var _transform = function(sel) { $(sel).toggleClass('robot'); } return = { transform: _transform } }(jQuery);
  • 34. // AMD module wraps everything in `define` define(function($) { var _transform = function(sel) { $(sel).toggleClass('robot'); } return = { transform: _transform } }(jQuery));
  • 35. // dependency array is the first parameter of define // dependencies mapped to parameters in the callback define([ 'jquery' ], function($) { var _transform = function(sel) { $(sel).toggleClass('robot'); } return = { transform: _transform } });
  • 36. // dependency array is the first parameter of define // dependencies mapped to parameters in the callback define([ 'jquery', 'underscore' ], function($, _) { var _transform = function(sel) { $(sel).toggleClass('robot'); } return = { transform: _transform } });
  • 37. // usage require([ 'transformer' ], function(transformer) { transformer.transform('.car'); });
  • 38. example website • common.js – code shared by all pages. • home/main.js – code unique to the home page.
  • 39. // common.js define([ 'jquery', 'ui/jquery.ui.core', 'ui/jquery.ui.widget' ], function($) { // setup code for all pages });
  • 40. // common.js define([ '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!
  • 41. // common.js requirejs.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($) {
  • 42. // home/main.js define([ 'common', 'ui/jquery.ui.dialog' ], function($) { $('.modal').dialog(); });
  • 43. // home/main.js define([ 'common', 'ui/jquery.ui.dialog' ], function($) { $('.modal').dialog(); }); // index.html <script src="require.js" data-main="home/main"></script>
  • 44. // home/main.js define([ 'common', 'ui/jquery.ui.dialog' ], function($) { $('.modal').dialog(); }); // index.html <script src="require.js" data-main="<?php echo $template ?>/main"></script>
  • 45. 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.
  • 46. 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.
  • 47. modular and maintainable but crappy performance: 7 requests!
  • 50. // build.js ({ modules: [ { name: "common" }, { name: "home/main" exclude: "common" } ] })
  • 51. // 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
  • 52. // example output Tracing dependencies for: common common.js ---------------- jquery.js ui/jquery.ui.core ui/jquery.ui.widget common.js
  • 53. // example output Tracing dependencies for: home/main home/main.js ---------------- ui/jquery.ui.dialog home/main.js
  • 54. // example output Uglifying file: common.js Uglifying file: home/main.js
  • 55. 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.
  • 56. 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).
  • 58. // build.js ({ baseUrl: "js-src/", // input folder dir: "js/", // output folder modules: [ { name: "common" }, { name: "home/main" exclude: "common" } ] })
  • 59. // 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
  • 60. even better performance with has.js feature detection library.
  • 61. define([ 'has' ], function($) { // add a test var re = /bdevb/; has.add('dev',re.test(window.location.search)); // use `has` if (has('dev')) { console.log('test'); } });
  • 62. define([ 'has' ], function($) { // add a test var re = /bdevb/; has.add('dev',re.test(window.location.search)); // use `has` if (has('dev')) { console.log('test'); } }); // index.html?dev // "test"
  • 63. // build.js ({ baseUrl: "js-src/", dir: "js/", has: { dev: false }, modules: [ … ] })
  • 64. // original if (has('dev')) { console.log('test'); }
  • 65. // original if (has('dev')) { console.log('test'); } // after r.js pre-processing if (false) { console.log('test'); }
  • 66. // original if (has('dev')) { console.log('test'); } // after r.js pre-processing if (false) { console.log('test'); } // after uglify post-processing // nothing – uglify strips dead code branches
  • 67. has.add('ie7-support', true); if (has('ie7-support') { // some godawful hack to fix something in ie7 }
  • 68. make it ultra high-performance
  • 69. 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)
  • 70. only 1 request… ever. • shaves 14k of boilerplate.
  • 71. 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.
  • 72. anyone not use jquery? “Study shows half of all websites use jQuery” – August, 2012
  • 73. // example of a jquery plugin used with a module define([ 'jquery', 'jquery.craftyslide' ], function($) { $('#slideshow').craftyslide(); });
  • 74. // closer look at `craftyslide.js` $.fn.craftyslide = function (options) { function paginate() { … } function captions() { … } function manual() { … } paginate(); captions(); manual(); }
  • 75. problem with jquery plugins they’re a black box. • not easily extendable. • not easily testable.
  • 76. problem with jquery plugins they’re a black box. • not easily extendable. • not easily testable. jquery ui set out to solve this with…
  • 78. 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).
  • 79. ui widgets the two things plugins suck at, widgets do really well: • they're fully extendable.
  • 80. simple javascript inheritence 25 lines of javascript sexiness: • constructors. • object-oriented inheritence. • access to overridden (super) methods.
  • 81. simple javascript inheritence 25 lines of javascript sexiness: • constructors. • object-oriented inheritence. • access to overridden (super) methods. also the foundation of ui widget extensibility.
  • 82. // example widget $.widget('ui.transformer', { options: { … }, _create: function() { … } );
  • 83. // example widget $.widget('ui.transformer', { options: { … }, _create: function() { … } ); // extending it $.widget('ui.autobot', $.ui.transformer, { // extend anything or everything });
  • 84. not-so simple javascript inheritence everything from simple javascript inheritence, plus: • namespaces. • public and private methods. • getters/setters. • disable/enable.
  • 85. ui widgets the two things plugins suck at, widgets do really well: • they're fully extendable. • they're tuned for testing.
  • 86. // if `craftyslide` were a widget $.widget('ui.craftyslide', { _create: function() { … this._paginate(); this._captions(); this._manual(); }, _paginate: function(){ … }, _captions: function(){ … }, _manual: function(){ … } );
  • 87. // adding triggers as hooks for testing $.widget('ui.craftyslide', { … _paginate: function(){ this._trigger('beforePaginate'); … this._trigger('afterPaginate'); }, … );
  • 88. // in your unit test function beforePaginate() { // test conditions } function afterPaginate() { // test conditions } $('#slideshow').craftyslide({ beforePaginate: beforePaginate, afterPaginate: afterPaginate });
  • 89. // plugin using `.on()` function manual() { … $pagination.on('click', function (e) { … }); }
  • 90. // plugin using `.on()` function manual() { … $pagination.on('click', function (e) { … }); } // widget using `._on()` manual: function() { this._on($pagination, { click: '_click' } }
  • 91. // `._on()` remembers all event bindings _on: function( element, handlers ) { … this.bindings = this.bindings.add( element ); },
  • 92. // `._on()` remembers all event bindings _on: function( element, handlers ) { … this.bindings = this.bindings.add( element ); }, // `.remove()` triggers a `remove` event this._on({ remove: "destroy" });
  • 93. // `._on()` remembers all event bindings _on: function( element, handlers ) { … this.bindings = this.bindings.add( element ); }, // `.remove()` triggers a `remove` event this._on({ remove: "destroy" }); // `.destroy()` cleans up all bindings // leaving the DOM pristine destroy: function() { … this.bindings.unbind( this.eventNamespace ); }
  • 94. // setup widget $('#slideshow').craftyslide(); // run tests … // teardown // calls `.destroy()` // which automatically unbinds all bindings $('#slideshow').remove();
  • 96. 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 } }); });
  • 97. 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.
  • 98. made possible via • fast file loading. • small file sizes. • avoiding DOM bottlenecks.
  • 101. <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 });
  • 102. <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 });
  • 103. // event delegation is similar $('#transformers').on('click', 'a', function() { // do something });
  • 104. // 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 });
  • 105. 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.
  • 106. how does this work with widgets? it doesnt – widget's pitfall is they are a DOM bottleneck.
  • 107. // example `lightbox` widget $('#gallery a').lightbox(); // widget depends on `this.element` $.widget('ui.lightbox', { _create: function() { this._on(this.element, { click: 'show' }); } });
  • 108. two workarounds • one for legacy widgets. • better approach for new widgets.
  • 109. // legacy widgets $(document).on('click', '#gallery a', function() { $(this) .lightbox() .lightbox('show'); });
  • 110. // new widgets $.widget('ui.lightbox', { _create: function() { var sel = this.options.selector; var handler = {}; handler['click ' + sel] = 'show’; this._on(handler); } });
  • 111. // 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' });
  • 112. 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!
  • 113. 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…
  • 114. how we’ve done this previously • document.load – the 80's of the internet. • document.DOMContentLoaded – the new load event!
  • 115. 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
  • 116. <ul id="transformers"> <li><a>Bumblebee</a></li> <li><a>Ratchet</a></li> <li><a>Ironside</a></li> </ul> <script> $('#transformers').slideshow(); </script>
  • 117. 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.
  • 118. mediator pattern to the rescue a central point of control that modules communicate through – instead of directly with each other.
  • 119. pubsub
  • 120. central point of control • publish • subscribe • unsubscribe
  • 121. it’s so easy • publish = $.trigger • subscribe = $.on • unsubscribe = $.off
  • 122. // in code var 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); }
  • 123. <ul id="transformers"> <li><a>Bumblebee</a></li> <li><a>Ratchet</a></li> <li><a>Ironside</a></li> </ul> <script> publish('load.transformers'); </script>
  • 124. define([ 'main' ], function() { subscribe('load.transformers', function() { $('#transformers').slideshow(); }); });
  • 125. 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.
  • 126. <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>
  • 127. // bootstrap.js // needs to be some global object // but we can clean it up afterwards document.queue = []; window.publish = function() { document.queue.push(arguments); }
  • 128. <script> publish('load.transformers'); </script> // document.queue = [['load.transformers']]
  • 129. // main.js define([ 'jquery' ], function($) { var proxy = $({}); window.publish = function() { proxy.trigger.apply(proxy, arguments); } window.unsubcribe = function() { proxy.off.apply(proxy, arguments); } …
  • 130. window.subscribe = function(event) { proxy.on.apply(proxy, arguments); });
  • 131. 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; } }); });
  • 133. 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.
  • 134. onesec
  • 136. 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.
  • 137.
  • 138.