78
Hardcore JavaScript Write it Right By Mike Wilcox February 2013 Wednesday, February 6, 2013

sys1 google 1104

Embed Size (px)

DESCRIPTION

m brevedescrio, bemcomoo valor afetivodos locaislistados. Descobrirecompartilharlugaresqueestofora dos guiastradicionaisdo toque colaborativodaideia. A PROPOSTA Teatros Museus Parques Esporte Bares Lojas Pode-se

Citation preview

Page 1: sys1 google 1104

Hardcore JavaScriptWrite it Right

By Mike WilcoxFebruary 2013

Wednesday, February 6, 2013

Page 2: sys1 google 1104

Readable Codehere(will make that book very |resistånt to pressure| to read.)

there(isn’t explained properly)

!bad Code is. like-a-book THATis badly formatted no indentation. incorrect punctuation misspelled words improper capitalizedation-ed. Or uneven.

?LINE HEIGHTS here() If “the” names of the char.acters start. Chang'ing, you dunno. where they are. && you+re not sure – WHAT they... are do-ing because it there(), the book w'ill bee pretty-difficult to [comprehend].

Wednesday, February 6, 2013

Page 3: sys1 google 1104

What do I know??

Douglas Crockford

me

Wednesday, February 6, 2013

Page 4: sys1 google 1104

What do I know??

Brendan Eichme

Wednesday, February 6, 2013

Page 5: sys1 google 1104

What do I know??Seriously…

Being a Dojo Committer means not only having your code and style scrutinized by know-it-all prima donnas, open source experts, but your results also get used by thousands of hacks that expect magic developers who expect quality code.

Wednesday, February 6, 2013

Page 6: sys1 google 1104

onPlayerParams = function(dfd){! dfd = dfd || new this.Deferred();! var o, p;! if(scriptNode && scriptNode.getAttribute("config")){! ! p = this.fixParams(scriptNode.getAttribute("config"));! ! p.swf = this.root + "player.swf";! }else if(this.embed()){! ! var parts = this.embed().getAttribute("src").split("?");! ! o = this.strToObj(parts[1]);! ! o.swf = parts[0];! ! p = this.fixParams(o);! }else if(!this.domReady){! ! this.ready(this, function(){! ! ! this.onPlayerParams(dfd);! ! }, true);! ! if(!p) return dfd;! }! if(p && p.vast){b.vast.parser.getXml(p.vast);}! return dfd;}

This code sucks!

Wednesday, February 6, 2013

Page 7: sys1 google 1104

Our ExcusesWe

can always go back and fix it later

No time for comments

The project manager needs this now

*I* can read it

My sloppy code means job security!

It was like that

when I started.

Wednesday, February 6, 2013

Page 8: sys1 google 1104

JavaScriptguide

Style

Wednesday, February 6, 2013

Page 9: sys1 google 1104

FormattingFormatting must be consistent. Otherwise little distractions make the code noisy and that much harder to read.var foo=”bar”+‘beer’+”bob”;for(var i=0;i<arguments.length;i++){}if(a&&b&&c&&d)return a;

Wednesday, February 6, 2013

Page 10: sys1 google 1104

FormattingUse single quotes, use spaces liberally, don’t use tiny, cryptic variable names and declare all variables at the beginning of the block.

var foo = ‘bar’ + ‘beer’ + ‘bob’;

var i;for( i = 0; i < arguments.length; i++ ){}

var apples = true,bananas = true,coconuts = true;

if( apples && bananas && coconuts ){return true;

}

Wednesday, February 6, 2013

Page 11: sys1 google 1104

Typical GuidesIndentation tabs not spaces

Spacing / whitespace

Curly braces rules

variable naming conventions

method naming conventions

Case: upper, lower, camel, Pascal

Dojo Style Guide

No Dojo

necessary!

http://dojotoolkit.org/community/styleGuide

Don’t be afraid of white space.

Wednesday, February 6, 2013

Page 12: sys1 google 1104

JSLint / JSHintIs it automated into your build?

It’s not just a suggestion - listen to it!

It’s more than to help you find errors

Helps promote consistency between devs

Prevents unintended consequences

If the linter thinks your code is ambiguous, so will other devs

Helps you target JIT compilers, resulting in faster code

Wednesday, February 6, 2013

Page 13: sys1 google 1104

Comments

Wednesday, February 6, 2013

Page 14: sys1 google 1104

OS comments vs production comments

short descriptions

save the lazy crap

No comments is like a book without chapters or page numbers

They aren’t just for your boss or your replacement

Why the hell did I write that??

Comments

Future

Self

Wednesday, February 6, 2013

Page 15: sys1 google 1104

Levels of Documenting1. Verbose comments on every method and module,

README and Wiki, instructions for setup and usage, guides to the software and how to edit it

2.Comments on most methods and modules, README with instructions for setup and a guide to what modules do

3.Brief comments on most methods and modules, README with instructions for setup

4.Unfinished code

Wednesday, February 6, 2013

Page 16: sys1 google 1104

The MythYou think your code is self documenting, huh? This is not self documenting:setCommand = function(c){ this.cmds.push(c); }run = function(){ … }

setListItemsWithDescritionsButNoThumbnails = function( … ){this.listItemDescriptions = listItemDescriptionsArgument;

}renderItemsWhichIsCalledAfterEveryPageResize = function(){ … }

This looks more like self documenting:

Wednesday, February 6, 2013

Page 17: sys1 google 1104

The MythWhat your self documenting code would look like:setListItemsWithDescritionsButNoThumbnails = function( … ){if(!this.itemsSetBoolenPreventSecondAttempt){this.itemsSetBoolenPreventSecondAttempt = true;this.listItemDescriptions = listItemDescriptionsArgument;this.renderItemsWhichIsCalledAfterEveryPageResize();this.onAfterRenderFunctionalStubEvent();

}

“Good clean code requires very consistent and good naming conventions that are concise, and which don't attempt to

embody an extended purpose”https://www.ibm.com/developerworks/mydeveloperworks/blogs/StylishGeek/entry/

bloated_names_and_the_myth_of_self_documenting_code11?lang=en

Wednesday, February 6, 2013

Page 18: sys1 google 1104

Don’t be that guyComment quality matters

function setParams(params){! // sets params}function setVideo(video){! // set video}

function setParams(params){! // sets parameters based on config property! // from script tag}function setVideo(videoPath){! // Sets the path for the video object}

When a dev writes crap like this, I want to paint him with meat paste and drop him on a mound of fire ants

Wednesday, February 6, 2013

Page 19: sys1 google 1104

Properties

Wednesday, February 6, 2013

Page 20: sys1 google 1104

Naming ConventionsShould be camel case

Upper case

Whole names, no abbreviations

This isn’t your father’s code. We have minifiers and gzip now. Use names we understand!

Exceptions for long or often used names: err for error, dfd for deferred, prop for property, app for application, etc.

i, k, j, etc, okay for iterators

Wednesday, February 6, 2013

Page 21: sys1 google 1104

Property BagsMultiple arguments (more than 3) are difficult to manage

An single argument as an object of options allows any or all properties to be passed without concern of method signature

Mixins allow for simple setting

Works with super constructors

Wednesday, February 6, 2013

Page 22: sys1 google 1104

function Widget(node, name, description, color, size){this.node = node;this.name = name || “Untitled”; this. description = description || “”;this.color = color || “#FF0000”;this.size = size || 100;this.code = “makes me sad”;

}new Widget({});

ARG-uments

Wednesday, February 6, 2013

Page 23: sys1 google 1104

function Widget( options ){util.mixin( this, options ); // Done!

}

Property Bag Example

var Widget = declare{name:‘Untitled’,description:’’,color:’#FF0000’,size:100,constructor: function( options ){

util.mixin(this, options); // Done!}

}

Even better is to set defaults and use a mixin that only overwrites and does not add undefined properties

Wednesday, February 6, 2013

Page 24: sys1 google 1104

var object = {! _x: 7,! get x() { return this.x + 1; },! set x( arg ) { this.x = arg / 2; }};

getters & setters

object.__defineGetter__("b", function() { return this.a + 1; });object.__defineSetter__("c", function(x) { this.a = x / 2; });

Initialization

After creation

ES5 getters and setters are still not widely used due to IE8. There are also issues as far as how inheritance would work. The super keyword is still in proposal.

Wednesday, February 6, 2013

Page 25: sys1 google 1104

var object = {! x: 7,! get: function( key ) { return this[ key ]; },! set: function( key, value ) { this[ key ] = value; }};

ES3 getters & settersInitialization

This is a very common and standardized pattern, even used in Node.js (Mongoose). It works with most library inheritance patterns.

Wednesday, February 6, 2013

Page 26: sys1 google 1104

object.watch( 'x', function( value ){! moveObject( x );});

object.observe( 'x', function( value ){! moveObject( x );});

Observers & Watchers

watch() is only available on Gecko with warnings of performance penalties. observe() is still an ES6 proposal.

Common solution is to simply connect to widget.set method with aspect.after.

Wednesday, February 6, 2013

Page 27: sys1 google 1104

<div class='Widget'>! <span data-bind='name'></name></div>

Widget = declare({! name:'Untitled',! set: function( key, value ){! ! this[ key ] = value;! ! if( this.bindings[ key ] ){! ! ! this.bindings[ key ].innerHTML = value;! ! }! }});

new Widget({ name: 'Bob' });

Binding

This common pattern is the key to all of these trendy MVC frameworks.

Wednesday, February 6, 2013

Page 28: sys1 google 1104

Functions and Methods

Wednesday, February 6, 2013

Page 29: sys1 google 1104

Naming ConventionsCamel case

Pascal case for constructors (Classes)

Should be verbs

getItems, setName, build, Widget, etc

Wednesday, February 6, 2013

Page 30: sys1 google 1104

function process(){}function state(){}function command(){}function structure(){}

Ambivalence

Those are not verbs.

process could be to perform operations or a series of steps

state could be to state your name, or the current application state

It’s not obvious what any of these do and they should at least be commented

Wednesday, February 6, 2013

Page 31: sys1 google 1104

function setImageProperties(){image.width = 320;image.height = 240;image.x = 100;image.y = 10;image.opacity = 0.9;updateImage();killPuppy();

}

Side Effects

Can you spot the side effect?

While side effects are not forbidden, you should still consider the consequences

Wednesday, February 6, 2013

Page 32: sys1 google 1104

Monolithic Functions fixParams = function(o){! var _vid = o.videoId || o.vid || o.siteId || "";! if(/\,/.test(_vid)){! ! o.media = [];! ! o.mediaParam = 'vid=' + _vid;! ! _vid.split(',').forEach(function(id){! ! ! o.media.push({videoId:id});! ! });! ! if(o.titles){! ! ! o.mediaParam += '&titles=' + o.titles;! ! ! o.titles.split(',').forEach(function(title, i){! ! ! ! o.media[i].caption = unescape(title);! ! ! });! ! ! delete o.titles;! ! }! ! delete o.videoId;! ! delete o.vid;! ! delete o.siteId;! }else if(o.media){! ! o.mediaParam = 'media=' + o.media;! }! var vid = o.videoId || o.vid || o.siteId || "";! var lid = o.locationId || o.lid;! var cid = Number(o.clientId) || o.cid;! if(lid === 1 || lid === "1" || !lid) lid = 0;! for(var nm in this.params){! ! if(o[nm] === undefined) o[nm] = this.params[nm];! }! if(!o.videoId && !o.siteId && !o.vid && o.media){! ! if(/siteId/.test(o.media)){! ! ! var pms = this.strToObj(unescape(o.media));! ! ! this.settings.siteId = pms.siteId;! ! }! }

Actual Code! See the whole thing here!

1970 called and wants their GOSUB back.

Requires extra cognition

Limits reusability

Even if it means more bytes, should be broken into smaller functions

Wednesday, February 6, 2013

Page 33: sys1 google 1104

function setListeners(){! this.domNode.addEventListener('onmousedown', this.onMouseDown);! this.domNode.addEventListener('onmouseup', this.onMouseUp);! this.domNode.addEventListener('onmousemove', this.onMouseMove);! this.domNode.addEventListener('onmouseover', this.onMouseOver);! this.domNode.addEventListener('onmouseout', this.onMouseOut);! this.domNode.addEventListener('onmouseenter', this.onMouseEnter);! this.domNode.addEventListener('onmouseleave', this.onMouseLeave);}

RepetitionThis ain’t Java. You shouldn’t have code like this.

Wednesday, February 6, 2013

Page 34: sys1 google 1104

['onmousedown', 'onmouseup', 'onmouseover'].forEach(function(event){! this.domNode.addEventListener(event, this[event]);}, this);

$(this.domNode).on('onmousedown, onmouseup, onmouseover', function(event){! handleMouseClick(event);!});

RepetitionJavaScript is a dynamic language and can handle repetition in multiple ways.

Wednesday, February 6, 2013

Page 35: sys1 google 1104

function parseDom(node){! function parseText(){}! function parseAttributes(){}! function parseChildren(){}! function getNodeType(){}! getNodeType(node);! parseText(node.innerHTML);! parseAttributes(node.attributes);! parseChildren(node.childNodes);}

Function in FunctionsFunctions inside of other functions are perfectly legitimate, but still should be used with care and consideration.

Wednesday, February 6, 2013

Page 36: sys1 google 1104

Function in FunctionsOften slower, as each time the outer is invoked, the inners are recreated

They are private and not accessible by other methods

If inners are not semantically tied very closely to the outer, the intention may be confusing

The inners should never access anything outside of the outer - aka, the application

Else what was the point?

Wednesday, February 6, 2013

Page 37: sys1 google 1104

LoopsWhere the biggest performance boost (or hit) can happen

Hot Loops

JIT compilers make assumptions, especially on loops

Not a good place for being tricky

Sparse arrays

Arrays with lots of “holes” will slow down the iteration

Some libraries, like Lo-Dash handle these holes and speed performance

Wednesday, February 6, 2013

Page 38: sys1 google 1104

Loops - for vs forEachfor is much faster, used in context and can be easily interrupted with a break or continue’d

for is a major chore to type - looks very “C”

forEach has the overhead of the function, and is used out of context unless the this argument is added which is an addition performance hit

forEach is much more finger friendly, and fine to use in low performance situations

map, some, every, filter etc. have same issues and should be used on small arrays

Wednesday, February 6, 2013

Page 39: sys1 google 1104

Functions in Loops

JSLint will complain. Listen to it!

Creates a new function on every iteration. Slow.

Fix this by moving the function outside of the loop and calling it. This allows for JIT prediction.

for( var i = 0; i < arguments.length; i++){! var handler = (function(node){! ! return node.addEventListener('click', blah);! })( arguments[i] );! handlers.push( handlers );}

Wednesday, February 6, 2013

Page 40: sys1 google 1104

for( var key in array ){doSomething( array[key] );

}

for vs for-infor-in is for objects, for is for arrays.

NO EXCEPTIONS!

Could access unwanted properties

Not a guarantee of order

Intent is not clear

In fact, it’s more of a WTF

If I see you do this I will give you a paper cut in the corner of your mouth and feed you lemons

Wednesday, February 6, 2013

Page 41: sys1 google 1104

Objects

Wednesday, February 6, 2013

Page 42: sys1 google 1104

var instance = {! doit: function(){ console.log('DOIT!'); },! subobject:{! ! submethod: function(){! ! ! doit(); // FAIL!! ! ! this.doit(); // FAIL!! ! ! parent.doit(); // No such thing!! ! }! }};instance.subobject.submethod();

Don’t fight “this”method

calls methodsu

b-object

This is a simplified version of a much larger problem

Wednesday, February 6, 2013

Page 43: sys1 google 1104

var instance = {! doit: function(){ console.log('DOIT!'); },! subobject:{! ! submethod: function(){! ! ! this.doit(); // works! ! }! }};instance.subobject.submethod =

bind(instance, instance.subobject.submethod);instance.subobject.submethod();

Don’t fight “this”You *could* bind the submethod to the parent object...

Of course, this begs the question of why you created subobject in the first place.

Wednesday, February 6, 2013

Page 44: sys1 google 1104

var instance = {! constructor: function(){! ! aop.after(this.subobject, 'submethod', this.doit.bind(this));! },! doit: function(){ console.log('DOIT!'); },! subobject:{! ! submethod: function(){}! }};

Don’t cross the beams!!One solution...

Understanding that communication only goes “down”, never “up” will go a long way toward clear code and simplified execution paths

Wednesday, February 6, 2013

Page 45: sys1 google 1104

Know thy selfself is the common variable name used to pass around and change context (this)

Because JavaScript is a closure based language, self can actually be very efficient. Believe it or not, this is slower:

var self = this;props.forEach(function(prop){! self[ prop.key ] = prop.value;});

props.forEach(function(prop){! this[ prop.key ] = prop.value;}, this);

http://kriszyp.name/2012/09/14/closure-based-instance-binding/Wednesday, February 6, 2013

Page 46: sys1 google 1104

var bind = function(ctx, func){! return function(){ func.apply(ctx, arguments); };};var instance = {! constructor: function(props){! ! var setProps = bind(this, this.setProps);! ! props.forEach(setProps);! },! setProps: function(p){! ! console.log(p);! }};instance.constructor([{a:1}, {b:2}]);

Alternative to selfContext binding basically uses call or apply under the hood

Wednesday, February 6, 2013

Page 47: sys1 google 1104

var instance = {! id:'binder',! constructor: function(props){! ! setTimeout(function(){! ! ! console.log(this.id);!! ! }.bind(this), 1);! }};instance.constructor();

ES5 bind()All modern browsers have Function.bind which can change context

Note that even though it’s built into the language, it’s not faster than self. It is for readability and convenience, not hot loops.

Wednesday, February 6, 2013

Page 48: sys1 google 1104

Hate thy self too muchself is like chocolate cake - some is good, too much will make you sickvar self = this;var onLoad = function(data){! self.title = data.title;! self.description = data.description;! self.setClients( data.clients );! self.on('finished', function(){! ! self.render( self.items );! ! setTimeout( function(){! ! ! self.emit( 'afterrender' );!! ! }, 1);! });};

Wednesday, February 6, 2013

Page 49: sys1 google 1104

Love thy self a littleOn solution is to immediately redirect to a properly bound method var instance = {! onDataLoaded: function(data){! ! // now set stuff! },! constructor: function(props){! ! var self = this;! ! var onLoad = function(data){! ! ! self.onDataLoaded(data);! ! };! }};

Wednesday, February 6, 2013

Page 50: sys1 google 1104

Don’t abuse your selfthis is specific; it can’t be changed so you always know to which object it points

self is ambiguous; it can point to many objects from any object, which obfuscates your intent

Don’t use self to shortcut better practices

Wednesday, February 6, 2013

Page 51: sys1 google 1104

Inheritance

Wednesday, February 6, 2013

Page 52: sys1 google 1104

Widget = function(props){! mixin(this, this.props);};Widget.prototype = {! render: function(){},! setItems: function(){}}

Prototypal InheritanceIf you are using the prototype keyword… you’re doing it wrong.

HMOHot Mike Opinion

Using prototype makes multiple inheritance difficult, and without some kind of AOP help, the super constructors won’t work.

Wednesday, February 6, 2013

Page 53: sys1 google 1104

var Base = dcl(null, {! declaredClass: 'Base',! constructor: function(params){! ! this.title = params.title;! }});

var Widget = dcl(null, {! declaredClass: 'Widget',! constructor: function(params){! ! this.className = params! },! render: function(){! ! this.setTemplate();! }});

dclA JavaScript package that implements OOP with mixins and AOP at both “class” and object level.

http://www.dcljs.org/about/

var Example1 = dcl([Base, Mixin1],{! constructor: function(params){! ! this.name = params.name;! },! render: function(){! ! this.prepareProps();! ! // call Widget.render! ! this.inherited();! }});

/*********************************/widget = new Example1({! title:'My Widget',! name:'widget',! className:'Widget'});

Wednesday, February 6, 2013

Page 54: sys1 google 1104

dcl / InheritanceBase classes can be reused, keeping code light - extremely important in JavaScript

Constructors are chained and called in all bases, which can’t be done in standard object creation, such as Object.create

super methods can be called with inherited(), so all base classes can use similar method names, keeping code standardized and less complex

For ES5 strict mode there is AOP inheritance

Wednesday, February 6, 2013

Page 55: sys1 google 1104

Other Design Patterns

Wednesday, February 6, 2013

Page 56: sys1 google 1104

Design Patterns

Functional (Imperative)

Declarative

Decorator

Composition

http://en.wikipedia.org/wiki/Design_Patterns

Design Patterns: Elements of Reusable Object-Oriented Software is a book with solutions to common problems in software design. The authors are often referred to as the Gang of Four.

Wednesday, February 6, 2013

Page 57: sys1 google 1104

Base! +! Item! ! +! ServerItem! ! ! +! ImageItem! ! ! ! +! ImageListItem! ! ! ! ! +! ImageListItemDescription! ! ! ! ! ! +! ImageListItemDescriptionClickable! ! ! ! ! ! ! +! ImageListItemDescriptionClickableDraggable

Over-InheritedOne reason for other solutions is to protect from over-inheritance

Based on more actual code from my Flash days!

Note however, JavaScript does not have the same inheritance restrictions as Java, C++, Flash, or others

Wednesday, February 6, 2013

Page 58: sys1 google 1104

define([! 'dojo/declare',! 'dojo/store/Memory',! 'dojo/store/Cache',! 'dojo/store/JsonRest',! 'dojo/store/Observable'], function( declare, Memory, Cache, JsonRest, Observable ){!!

});

DeclarativeA problem faced by libraries is allowing the dev to choose discrete segments of code instead of kitchen sink solutions

The dev can dynamically create their own constructor with the mixins provided

var Store = declare( Memory, Cache, JsonRest );var store = new Store( webserviceUrl );

Wednesday, February 6, 2013

Page 59: sys1 google 1104

define([], function( declare, Memory, Cache, JsonRest, Observable ){!! var Store = declare( Memory, Cache, JsonRest );! var store = new Store( webserviceUrl );

});

Decorator

Decorators are not very common, but they do solve a few problems like working with existing objects that you can’t change, or creating two objects from the same base with different functionality.

observableStore = Observable( store );cacheableStore = Cache( observableStore );

Wednesday, February 6, 2013

Page 60: sys1 google 1104

Widget = {! constructor: function(model){! ! this.model = model;!! },! get: function(key){! ! return this.model.get(key);! }}

CompositionComposition often makes sense semantically. Here the model encapsulates properties and functionality.

Wednesday, February 6, 2013

Page 61: sys1 google 1104

FunctionalDon’t.Just don’t.Friends don’t let friends write functional.

HMOHot Mike Opinion

Wednesday, February 6, 2013

Page 62: sys1 google 1104

App Structure

Wednesday, February 6, 2013

Page 63: sys1 google 1104

require.jsYou are using it, aren’t you?

Globals are SO 2011

Globals can clash with other code, and they do not garbage collect

require.js provides a mini-framework, enforcing packages, namespaces, and modules

Wednesday, February 6, 2013

Page 64: sys1 google 1104

Naming and ArrangingDon't expect to cram it all into preconceived model-view-controller folders, it's too limiting, and the app will grow out of it

Remember, the code path flows down, not up, so the deeper modules should not have access to root modules

Wednesday, February 6, 2013

Page 65: sys1 google 1104

define([], function(){! var items = [];! function setItem(item){! ! items.push(item);! }! function getItem(idx){! ! return items[idx];! }! return {! ! setItem:setItem,! ! getItem:getItem! };});

Module APIsModules can use private variables, but not to hide or protect anybody - use them to help provide a clean API. And if you are doing so - make it a clear intent!

Wednesday, February 6, 2013

Page 66: sys1 google 1104

Wiring

Wednesday, February 6, 2013

Page 67: sys1 google 1104

Wiring Typestight coupling (direct access)

AOP

events

pubsub

callbacks

promises

Wednesday, February 6, 2013

Page 68: sys1 google 1104

define([! './foo',! '../../views/widgets/utils/thinger'], function(foo, thinger){! foo.doStuff();! thinger.stopStuff();});

Tight CouplingPros:

The intent is quite clearRequires no additional libraries of fancy code

Cons:Over-use between modules can create a hairballCan break encapsulation

require.js allows for clear paths to distant modules, but if you are connecting to something this “far” away, you should probably do some restructuring

Wednesday, February 6, 2013

Page 69: sys1 google 1104

define([! 'aop',! './items'], function(aop, items){! function onLoaded(data){! ! console.log(data);! }!! aop(items, 'onLoad', onLoaded);});

AOPUses JavaScript’s dynamic, mutable languageDoesn’t overwrite method, so many connections can be madeMake sure to create names to indicate they are event-methods

Wednesday, February 6, 2013

Page 70: sys1 google 1104

define(['dcl', 'Events'], function(dcl, Events){! return new dcl(Events, {! ! onDataLoaded: function(data){! ! ! this.emit('dataloaded', data);! ! }! });});define(['./dataLoader'], function(dataLoader){! function onDataLoaded(data){! ! console.log(data);! }! dataLoader.on('dataloaded', onDataLoaded);});

EventsThe new hotnessMultiple connections can be madeIntent is clear - obvious they are events and what they do

Wednesday, February 6, 2013

Page 71: sys1 google 1104

define(['pubsub'], function(pubsub){! pubsub.publish('/module/loaded', {success:true});});define(['pubsub'], function(pubsub){! pubsub.subscribe('/module/loaded', function(object){! ! console.log('load success:', object.success);! });});

pubsubPros:

Library code is very simpleCan access distant areas of app

Cons:Not guaranteed - pub can fire before sub is readyCan be hard to follow code paths between unrelated modules Over-use can lead to race conditions

Wednesday, February 6, 2013

Page 72: sys1 google 1104

define([], function(){! return {! ! loadData: function(callback){! ! ! xhr('/getdata', {! ! ! ! load: function(data){! ! ! ! ! callback(data);! ! ! ! }});}};});define(['./instance'], function(instance){! function onDataLoaded(data){! ! console.log(data);! }! instance.loadData(onDataLoaded);});

callbacksPros: Old-school, simple way of connecting async; clear code pathCons: Only one connection, no propagation, multiple callback nesting can cause “callback hell”

Wednesday, February 6, 2013

Page 73: sys1 google 1104

define(['Deferred'], function(Deferred){! return function(){! ! var dfd = new Deferred();! ! xhr('/getdata', {! ! ! load: function(data){! ! ! ! dfd.resolve(data);! ! ! }!! ! });! ! return dfd;! }});define(['./loader'], function(loader){! loader().then(function(data){! ! console.log(data);! });});

promises / deferreds

Wednesday, February 6, 2013

Page 74: sys1 google 1104

promises / deferredsPros:

AsyncA when() library can handle both async and syncTrendy (everybody is doing it!!)Multiple connections can be madePropagates, and can be stopped

Cons:Libraries are somewhat complexRequires (a lot) more code than a callbackHas a tendency to swallow errors unexpectedlyCan dominate the stacktrace and make it hard to debug errors

Wednesday, February 6, 2013

Page 75: sys1 google 1104

Conclusion

Wednesday, February 6, 2013

Page 76: sys1 google 1104

Refactor!Little projects always become big projects

You will never have all the information up front

Sales can turn your app into Frankenstein

Wednesday, February 6, 2013

Page 77: sys1 google 1104

Committee Refactor!Make it small. People

like small.

But make it big inside.

Oh! And four doors.

Small with lots of doors.

My son says it would

be cool if you could camp in it.

It sure is tall. Can

you make it LOOK short?

Don’t spend too much on

the trim.

Don’t spend too much on

the wheels.

Wednesday, February 6, 2013

Page 78: sys1 google 1104

Wednesday, February 6, 2013