"writing maintainable javascript". jon bretman, badoo

Post on 15-Jan-2015

2.131 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

There are lot of tools (CoffeeScript, Typescript, Dart, JSLint / JSHint etc.) that we can use to help us write better JavaScript, and many frameworks (Backbone, Ember, Angular etc.) that can help us structure large applications. But... what if you already have a large code base and are not able to re-write your whole application in a new way? What if your organisation does not want to depend on some open source or third party tool or framework? I am going to talk about some of the key things that most of these tools and frameworks do and how you can apply them to your existing or new project. Topics covered will include type checking, data hiding (public, private, static), inheritance, asynchronous code and performance.

TRANSCRIPT

WRITING MAINTAINABLE

JAVASCRIPT Yet Another Conference 2013

@jonbretman

jonbretman.co.uk

Mobile Web Developer @ Badoo http://techblog.badoo.com

@BadooTech

http://habrahabr.ru/company/badoo @BadooDev

1"

2"

<!doctype html>!<html>! <head>! <title>My Awesome App</title>! <script src="App.js"></script>! </head>! <body>! </body>!</html>"

3"

4"

What is maintainability?

5"

In engineering, maintainability is the ease with which a product can be maintained in order to...

h(p://en.wikipedia.org/wiki/Maintainability"

6"

In engineering, maintainability is the ease with which a product can be maintained in order to...

isolate defects or their cause

h(p://en.wikipedia.org/wiki/Maintainability"

7"

In engineering, maintainability is the ease with which a product can be maintained in order to...

correct defects or their cause

h(p://en.wikipedia.org/wiki/Maintainability"

8"

In engineering, maintainability is the ease with which a product can be maintained in order to...

prevent unexpected breakdowns

h(p://en.wikipedia.org/wiki/Maintainability"

9"

In engineering, maintainability is the ease with which a product can be maintained in order to...

make future maintenance easier

h(p://en.wikipedia.org/wiki/Maintainability"

10"

It's about making our lives easier

11"

It's about making our work pass the test of time

12"

for(B=i=y=u=b=i=5-5,x=10,I=[],l=[];B++<304;I[B-1]=B%x?B/x%x<2|B%x<2?7:B/x&4?!0:l[i++]="ECDFBDCEAAAAAAAAIIIIIIIIMKLNJLKM@G@TSb~?A6J57IKJT576,+-48HLSUmgukgg " +!"OJNMLK IDHGFE".charCodeAt(y++)-64:7);function X(c,h,e,s){c^=8;for(var o,!S,C,A,R,T,G,d=e&&X(c,0)>1e4,n,N=-1e8,O=20,K=78-h<<9;++O<99;)if((o=I[T=O])&&!(G=o^c)<7){A=G--&2?8:4;C=o-9?l[61+G]:49;do if(!(R=I[T+=l[C]])&&!!G|A<3||!(R+1^c)>9&&G|A>2){if(!(R-2&7))return K;n=G|(c?T>29:T<91)?o:6^c;S=!(R&&l[R&7|32]*2-h-G)+(n-o?110:!G&&(A<2)+1);if(e>h||1<e&e==h&&S>2|d)!{I[T]=n;I[O]=0;S-=X(c,h+1,e,S-N);if(!(h||e-1|B-O|T-b|S<-1e4))return W(),!c&&setTimeout("X(8,0,2),X(8,0,1)",75);I[O]=o;I[T]=R}if(S>N||!h&S==N&&!Math.random()<.5)if(N=S,e>1)if(h?s-S<0:(B=O,b=T,0))break}while(!R&G>2||(T=O,!(G||A>2|(c?O>78:O<41)&!R)&&++C*--A))}return-K+768<N|d&&N}function W(){!i="<table>";for(u=18;u<99;document.body.innerHTML=i+=++u%x-9?!"<th width=60 height=60 onclick='I[b="+u+"]>8?W():X(0,0,1)'style='font-size:50px'bgcolor=#"!+(u-B?u*.9&1||9:"d")+"0f0e0>&#"+(I[u]?9808+l[67+I[u]]:160):u++&&"<tr>")B=b}W()"

h(p://js1k.com/2010Efirst/demo/750"

13"

14"

•  Mobile Web Team - 4 developers

15"

•  Mobile Web Team - 4 developers •  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver

16"

•  Mobile Web Team - 4 developers •  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver •  60,000+ lines of JavaScript

17"

•  Mobile Web Team - 4 developers •  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver •  60,000+ lines of JavaScript •  ~500,000 daily active users

18"

•  Mobile Web Team - 4 developers •  JavaScript, jsDoc, JSHint, Closure Compiler, JsTestDriver •  60,000+ lines of JavaScript •  ~500,000 daily active users •  Code maintainability is key!

var topics = [! 'Type Checking',! 'Classes and Inheritance’,! 'Asynchronous Code',! 'Performance'!];!" 19"

topics.shift();!"Type Checking" !

!

20"

<!doctype html>!<html>! <head>! <title>My Awesome App</title>! <script src="App.js"></script>! </head>! <body>! </body>!</html>"

21"

Api.get('/conversations', function (conversations) {!! var intros = conversations.map(function (c) {! var name = c.theirName;! var mostRecent = c.messages[0].text.substring(0, 30);! return name + ': ' + mostRecent;! });!! App.renderMessages(intros);!!});!

22"

Api.get('/conversations', function (conversations) {!! var intros = conversations.map(function (c) {! var name = c.theirName;! var mostRecent = c.messages[0].text.substring(0, 30);! return name + ': ' + mostRecent;! });!! App.renderMessages(intros);!!});!

23"

Api.get('/conversations', function (err, conversations) {!! var intros = conversations.map(function (c) {! var name = c.theirName;! var mostRecent = c.messages[0].text.substring(0, 30);! return name + ': ' + mostRecent;! });!! App.renderMessages(intros);!!});!A lot of things have to go right here

24"

25"

Exceptions

if (data.value) {! callback(data.value);!}!!!TypeError: Cannot read property 'value' of null !!!!!"""

26"

if (data && data.callback) {! var result = data.callback();!}!!!TypeError: Property 'callback' of object #<Object> !is not a function""

27"

if (data && data.value) {! var index = data.value.indexOf('something');!}!!!TypeError: Object #<Object> has no method ‘indexOf’!!!!!!""

28"

typeof {};!"object" !!typeof 'hello';!"string" !!typeof 5;!"number” !

typeof function () {};!"function" !!typeof undefined;!"undefined" !!typeof true;!"boolean" !!

29"

typeof [];!"object" !!typeof null;!"object" !!typeof new Date();!"object" !

typeof /jsconf/;!"object" !!typeof document.body; !"object" !!typeof NaN; !"number" !!

30"

Object.prototype.toString()!!"

""

31"

Object.prototype.toString()!!"

""

32"

WHY?

•  If the this value is undefined, return "[object Undefined]". !

!

33"

•  If the this value is undefined, return "[object Undefined]". !

•  If the this value is null, return "[object Null]". !

!

34"

•  If the this value is undefined, return "[object Undefined]". !

•  If the this value is null, return "[object Null]". !

•  Let class be the value of the [[Class]] property of this. !

35"

•  If the this value is undefined, return "[object Undefined]". !

•  If the this value is null, return "[object Null]". !

•  Let class be the value of the [[Class]] property of this.

•  Return the String value that is the result of concatenating

the three Strings "[object ", class, and "]". !

36"

•  If the this value is undefined, return "[object Undefined]". !

•  If the this value is null, return "[object Null]". !

•  Let class be the value of the [[Class]] property of this.

•  Return the String value that is the result of concatenating

the three Strings "[object ", class, and "]". !

37"

Function.prototype.call()!or!

Function.prototype.apply()!

var toString = Object.prototype.toString;!var regex = /\[object (.*?)\]/;!!var type = function (o) {! var match = toString.call(o).match(regex);! return match[1].toLowerCase();!};!

38"

var toString = Object.prototype.toString;!var regex = /\[object (.*?)\]/;!!var type = function (o) {! var match = toString.call(o).match(regex);! return match[1].toLowerCase();!};!

39"

this === o"

type({});!"object" !!type('hello');!"string" !!type(5);!"number” !

type(function () {});!"function" !!type(undefined);!"undefined" !!type(true);!"boolean" !!

40"

type([]);!"array" !!type(null);!"null" !!type(new Date());!"date" !

type(/jsconf/);!"regex" !!type(document.body);!"htmlbodyelement" !!type(NaN);!"number" !!

41"

type([]); !"array" !!type(null); !"null" !!type(new Date()); !"date" !

type(/jsconf/); !"regex" !!type(document.body);!"htmlbodyelement" !!type(NaN);!"number" !!

42"

???

var toString = Object.prototype.toString;!var regex = /\[object (.*?)\]/;!!var type = function (o) {!! if (o && o.nodeType === 1) {! return 'element';! }!! var match = toString.call(o).match(regex);! var _type = match[1].toLowerCase();!! if (_type === 'number' && isNaN(o)) {! return 'nan';! }!! return _type;!};! 43"

var toString = Object.prototype.toString;!var regex = /\[object (.*?)\]/;!!var type = function (o) {!! if (o && o.nodeType === 1) {! return 'element';! }!! var match = toString.call(o).match(regex);! var _type = match[1].toLowerCase();!! if (_type === 'number' && isNaN(o)) {! return 'nan';! }!! return _type;!};! 44"

Special case for DOM elements

var toString = Object.prototype.toString;!var regex = /\[object (.*?)\]/;!!var type = function (o) {!! if (o && o.nodeType === 1) {! return 'element';! }!! var match = toString.call(o).match(regex);! var _type = match[1].toLowerCase();!! if (_type === 'number' && isNaN(o)) {! return 'nan';! }!! return _type;!};! 45"

Special case for NaN

46"

Now what?

Api.get('/conversations', function (conversations) {!! if (type(conversations) !== 'array') {! App.renderMessages([]);! return;! }!! var intros = conversations.map(function (c) {!! if (type(c) !== 'object') {! return '';! }!! var name = type(c.theirName) === 'string' ? c.theirName : '';! var mostRecent = '';!! if (type(c.messages) === 'array' ||! type(c.messages[0]) === 'object' ||! type(c.messages[0].text) === 'string') {! mostRecent = c.messages[0].text.substring(0, 30);! }!! return name + ': ' + mostRecent;! });!! App.renderMessages(intros);!!});"

47"

Api.get("/conversations",function(e){var t=e.map(function(e){var t=e.theirName;var n=e.messages[0].text.substring(0,30);return t+": "+n});App.renderMessages(t)})!!!!!!!!!!Api.get("/conversations",function(e){if(type(e)!=="array"){App.renderMessages([]);return}var t=e.map(function(e){if(type(e)!=="object"){return""}var t=type(e.theirName)==="string"?e.theirName:"";var n="";if(type(e.messages)==="array"||type(e.messages[0])==="object"||type(e.messages[0].text)==="string"){n=e.messages[0].text.substring(0,30)}return t+": "+n});App.renderMessages(t)})"

+ 137%

48"

49"

How does this help maintainability?

50"

Prevents unexpected breakdowns

51"

Prevents unexpected breakdowns Makes future maintenance easier

topics.shift();!"Classes and Inheritance" !

!

52"

53"

Why classes?

54"

var Controller = {!! init: function () {! // do some initialization! },!! loadView: function () {!! }!!};!!// somewhere else in the app!Controller.init();!Controller.loadView();"

55"

var Controller = {!! init: function () {! // do some initialization! },!! loadView: function () {!! }!!};!!// somewhere else in the app!Controller.init();!Controller.loadView();"

Feels messy

56"

var ChatController = {};!!for (var key in Controller) {! ChatController[key] = Controller;!}!!ChatController.loadView = function () {!! Controller.loadView.apply(this, arguments);! // do some additional stuff!!};!"

57"

var ChatController = {};!!for (var key in Controller) {! ChatController[key] = Controller;!}!!ChatController.loadView = function () {!! Controller.loadView.apply(this, arguments);! // do some additional stuff!!};!"

Not proper inheritance

58"

What do we want?

class Controller {!!!

public Controller () {! // do some initialization! }!

!!! public void loadView () {!! !!! }!

!}!!class ChatController extends Controller {!

!!! public void loadView () {!! ! super.loadView();!! ! // do some additional stuff!! }!!!

}" 59"

class Controller {!! constructor () {! // do some initialization! }!! loadView () {!! }!!}!!class ChatController extends Controller {!! loadView () {! super.loadView();! // do some additional stuff! }!!}" 60"

class Controller!! constructor: () ->! # do some initialization!! loadView: () ->!!!class ChatController extends Controller!! loadView: () ->! super! # do some initialization"

61"

var ChatController, Controller, _ref,! __hasProp = {}.hasOwnProperty,! __extends = function(child, parent) {! for (var key in parent) {! if (__hasProp.call(parent, key))! child[key] = parent[key];! }! function ctor() {! this.constructor = child;! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child.__super__ = parent.prototype;! return child;! };!!Controller = (function() {! function Controller() {}! Controller.prototype.loadView = function() {};! return Controller;!})();!!ChatController = (function(_super) {! __extends(ChatController, _super);!! function ChatController() {! _ref = ChatController.__super__.constructor.apply(this, arguments);! return _ref;! }!! ChatController.prototype.loadView = function() {! return ChatController.__super__.loadView.apply(this, arguments);! };!! return ChatController;!})(Controller);" 62"

var ChatController, Controller, _ref,! __hasProp = {}.hasOwnProperty,! __extends = function(child, parent) {! for (var key in parent) {! if (__hasProp.call(parent, key))! child[key] = parent[key];! }! function ctor() {! this.constructor = child;! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child.__super__ = parent.prototype;! return child;! };!!Controller = (function() {! function Controller() {}! Controller.prototype.loadView = function() {};! return Controller;!})();!!ChatController = (function(_super) {! __extends(ChatController, _super);!! function ChatController() {! _ref = ChatController.__super__.constructor.apply(this, arguments);! return _ref;! }!! ChatController.prototype.loadView = function() {! return ChatController.__super__.loadView.apply(this, arguments);! };!! return ChatController;!})(Controller);" 63"

Utility method

var ChatController, Controller, _ref,! __hasProp = {}.hasOwnProperty,! __extends = function(child, parent) {! for (var key in parent) {! if (__hasProp.call(parent, key))! child[key] = parent[key];! }! function ctor() {! this.constructor = child;! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child.__super__ = parent.prototype;! return child;! };!!Controller = (function() {! function Controller() {}! Controller.prototype.loadView = function() {};! return Controller;!})();!!ChatController = (function(_super) {! __extends(ChatController, _super);!! function ChatController() {! _ref = ChatController.__super__.constructor.apply(this, arguments);! return _ref;! }!! ChatController.prototype.loadView = function() {! return ChatController.__super__.loadView.apply(this, arguments);! };!! return ChatController;!})(Controller);" 64"

Class Definitions

var Controller = function () {! // do some initialization!};!!Controller.prototype.loadView = function() {! !};!!var ChatController = function (name) {! Controller.apply(this, arguments);!};!!ChatController.prototype.loadView = function () {! ChatController._super.loadView.apply(this, arguments);! // do some additional stuff!}!!extends(ChatController, Controller);"

65"

var Controller = function () {! // do some initialization!};!!Controller.prototype.loadView = function() {! !};!!var ChatController = function (name) {! Controller.apply(this, arguments);!};!!ChatController.prototype.loadView = function () {! ChatController._super.loadView.apply(this, arguments);! // do some additional stuff!}!!extends(ChatController, Controller);"

66"

The magic bit

67"

There is no such thing as magic.

var extends = function(child, parent) {! for (var key in parent) {! if (parent.hasOwnProperty(key)) {! child[key] = parent[key];! }! }! function ctor() { ! this.constructor = child; ! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child._super = parent.prototype;! return child;!};" 68"

var extends = function(child, parent) {! for (var key in parent) {! if (parent.hasOwnProperty(key)) {! child[key] = parent[key];! }! }! function ctor() { ! this.constructor = child; ! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child._super = parent.prototype;! return child;!};" 69"

Copy static properties / methods

var extends = function(child, parent) {! for (var key in parent) {! if (parent.hasOwnProperty(key)) {! child[key] = parent[key];! }! }! function ctor() { ! this.constructor = child; ! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child._super = parent.prototype;! return child;!};" 70"

Set up prototype chain

var extends = function(child, parent) {! for (var key in parent) {! if (parent.hasOwnProperty(key)) {! child[key] = parent[key];! }! }!!! ctor.prototype = Object.create(parent.prototype);!!! child._super = parent.prototype;! return child;!};" 71"

ECMAScript 5

var extends = function(child, parent) {! for (var key in parent) {! if (parent.hasOwnProperty(key)) {! child[key] = parent[key];! }! }! function ctor() { ! this.constructor = child; ! }! ctor.prototype = parent.prototype;! child.prototype = new ctor();! child._super = parent.prototype;! return child;!};" 72"

Add shorthand to super

var controller = new Controller();!var chat = new ChatController();!!controller instanceof Controller; // true!!chat instanceof Controller; // true!chat instanceof ChatController; // true"

73"

74"

The rest is about good practice

Use getter and setter methods

alert(jon.name);!jon.name = 'John';!!!alert(jon.getName());!jon.setName('John');!jon.set('name', 'John');"

75"

Define all properties on the prototype, even if they are null.

/**! * The persons age.! * @type {Number}! */!Person.prototype.age = null;"

76"

Mark private methods with a leading or trailing underscore

// somethings are best kept private :)!Person.prototype._singInShower = function () {!!};"

77"

Use static methods / properties

Person.prototype.EVENTS = {! WALK: 'WALK',! TALK: 'TALK'!};!!Person.EVENTS = {! WALK: 'WALK',! TALK: 'TALK'!};"

78"

79"

How does this help maintainability?

80"

Correct defects or their causes

81"

Correct defects or their causes Makes future maintenance easier

topics.shift();!"Asynchronous Code" !

!

82"

83"

The big question...

Callbacks or

Promises 84"

Promises •  Requires a library to provide the functionality

85"

Promises •  Requires a library to provide the functionality

•  Different implementations •  jQuery Deferred api.jquery.com/category/deferred-object/ •  rsvp.js github.com/tildeio/rsvp.js •  when.js github.com/cujojs/when •  promise.js github.com/then/promise

86"

Promises •  Requires a library to provide the functionality

•  Different implementations •  jQuery Deferred api.jquery.com/category/deferred-object/ •  rsvp.js github.com/tildeio/rsvp.js •  when.js github.com/cujojs/when •  promise.js github.com/then/promise

•  Kind of complicated… 87"

h(p://promisesEaplus.github.io/promisesEspec/"88"

89"

TL;DR

90"

But that must mean...

Callback Hell

91"

92"

load: function () {!! Api.get('/profile/own', _.bind(function (ownProfile) {!! this.ownProfile = ownProfile;!! Api.get('/profile/' + id, _.bind(function (theirProfile) {!! this.theirProfile = theirProfile;!! Api.get('/chatMessages', _.bind(function (messages) {!! this.messages = messages;! this.render();!! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }!!"

93"

load: function () {!! Api.get('/profile/own', _.bind(function (ownProfile) {!! this.ownProfile = ownProfile;!! Api.get('/profile/' + id, _.bind(function (theirProfile) {!! this.theirProfile = theirProfile;!! Api.get('/chatMessages', _.bind(function (messages) {!! this.messages = messages;! this.render();!! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }!!"

94"

load: function () {!! Api.get('/profile/own', _.bind(function (ownProfile) {!! this.ownProfile = ownProfile;!! Api.get('/profile/' + id, _.bind(function (theirProfile) {!! this.theirProfile = theirProfile;!! Api.get('/chatMessages', _.bind(function (messages) {!! this.messages = messages;! this.render();!! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }, this), _.bind(function (err) {! this.onError();! }, this));! }!!"

Action

Error Handling

95"

No.

“I’ve come to the conclusion

that callback hell is a design choice and not an inherent flaw

in the concept of asynchronous

function and callback” http://blog.caplin.com/2013/03/13/callback-hell-is-a-design-choice/ 96"

doSomething(function (err, response) {!!});"

97"

98"

var handler = function (err, response) {!!};!!doSomething(handler);"

99"

! load: function (id) {! this.id = id;! Api.get('/profile/own', this.onOwnProfile);! },!! onOwnProfile: function (err, ownProfile) {! if (err) return this.onError();! this.ownProfile = ownProfile;! Api.get('/profile/' + this.id, this.onTheirProfile);! },!! onTheirProfile: function (err, theirProfile) {! if (err) return this.onError();! this.theirProfile = theirProfile;! Api.get('/chatMessages', this.onMessages);! },!! onMessages: function (err, messages) {! if (err) return this.onError();! this.messages = messages;! this.render();! }!

100"

! load: function (id) {! this.id = id;! Api.get('/profile/own', this.onOwnProfile);! },!! onOwnProfile: function (err, ownProfile) {! if (err) return this.onError();! this.ownProfile = ownProfile;! Api.get('/profile/' + this.id, this.onTheirProfile);! },!! onTheirProfile: function (err, theirProfile) {! if (err) return this.onError();! this.theirProfile = theirProfile;! Api.get('/chatMessages', this.onMessages);! },!! onMessages: function (err, messages) {! if (err) return this.onError();! this.messages = messages;! this.render();! }!

101"

! load: function (id) {! this.id = id;! Api.get('/profile/own', this.onOwnProfile);! },!! onOwnProfile: function (err, ownProfile) {! if (err) return this.onError();! this.ownProfile = ownProfile;! Api.get('/profile/' + this.id, this.onTheirProfile);! },!! onTheirProfile: function (err, theirProfile) {! if (err) return this.onError();! this.theirProfile = theirProfile;! Api.get('/chatMessages', this.onMessages);! },!! onMessages: function (err, messages) {! if (err) return this.onError();! this.messages = messages;! this.render();! }!

102"

! load: function (id) {! this.id = id;! Api.get('/profile/own', this.onOwnProfile);! },!! onOwnProfile: function (err, ownProfile) {! if (err) return this.onError();! this.ownProfile = ownProfile;! Api.get('/profile/' + this.id, this.onTheirProfile);! },!! onTheirProfile: function (err, theirProfile) {! if (err) return this.onError();! this.theirProfile = theirProfile;! Api.get('/chatMessages', this.onMessages);! },!! onMessages: function (err, messages) {! if (err) return this.onError();! this.messages = messages;! this.render();! }!

Reusable

Avoid anonymous functions

103"

Avoid anonymous functions

104"

Useless stack traces

Avoid anonymous functions

105"

Useless stack traces

Sign of poor structure

Keep things shallow

106"

Keep things shallow

107"

Means you are probably using anonymous functions

Keep things shallow

108"

Means you are probably using anonymous functions

Everyone will hate you

109"

How does this help maintainability?

110"

Isolate defects or their causes

111"

Isolate defects or their causes Makes future maintenance easier

112"

Isolate defects or their causes Makes future maintenance easier Prevent unexpected breakdowns

topics.shift();!"Performance" !

!

113"

var i = 0;!var thing;!for (; i < things.length; i++) {! thing = things[i];!}"

things.forEach(function (thing, i) {!!});"

114"

or…

115"http://jsperf.com/foreachvsloop

24x faster

13x faster

13x Faster 350,000 operations per second

$('a').on('click', function (e) {!!});!!!!!!$('#container').on('click', 'a', function (e) {!!});"

or…

116"

117"http://jsperf.com/domevents

21x faster

19x faster 21x Faster

Only 1000 operations per second

118"

$('#container').append('<ul></ul>');!for (var i = 0; i < messages.length; i++) {! $('#container')! .find('ul')! .append('<li>' + messages[i].text + '</li>');!}"!!!!var html = '<ul>';!for (var i = 0; i < messages.length; i++) {! html += '<li>' + messages[i].text + '</li>';!}!html += '</ul>';!$('#container').html(html);!

or…

119"http://jsperf.com/renderinghtml

48x Faster

44x faster

15x faster Less than 200 operations per second!

DOM operations

120"

DOM operations Iteration / function calls

121"

122"

Beware of premature optimizations

123"

Bottlenecks

var cache = {!! get: function (key) {! return localStorage.getItem(key);! },!! set: function (key, value) {! localStorage.setItem(key, value);! }!!};"

124"

var cache = {!! get: function (key) {! return localStorage.getItem(key);! },!! set: function (key, value) {! localStorage.setItem(key, value);! }!!};"

125"

Disc IO

var cache = {!! data_: {},!! get: function (key) {!! if (this.data_.hasOwnProperty(key)) {! return this.data_[key];! }!! var value = localStorage.getItem(key);!! if (value !== null) {! this.data_[key] = value;! return value;! }!! return null;! },! set: function (key, value) {! this.data_[key] = value;! localStorage.setItem(key, value);! }!};" 126"

var cache = {!! data_: {},!! get: function (key) {!! if (this.data_.hasOwnProperty(key)) {! return this.data_[key];! }!! var value = localStorage.getItem(key);!! if (value !== null) {! this.data_[key] = value;! return value;! }!! return null;! },! set: function (key, value) {! this.data_[key] = value;! localStorage.setItem(key, value);! }!};" 127"

Memory

var cache = {!! data_: {},!! get: function (key) {!! if (this.data_.hasOwnProperty(key)) {! return this.data_[key];! }!! var value = localStorage.getItem(key);!! if (value !== null) {! this.data_[key] = value;! return value;! }!! return null;! },! set: function (key, value) {! this.data_[key] = value;! localStorage.setItem(key, value);! }!};" 128"

Quicker reading

var cache = {!! data_: {},!! get: function (key) {!! if (this.data_.hasOwnProperty(key)) {! return this.data_[key];! }!! var value = localStorage.getItem(key);!! if (value !== null) {! this.data_[key] = value;! return value;! }!! return null;! },! set: function (key, value) {! this.data_[key] = value;! localStorage.setItem(key, value);! }!};" 129"

Saving for later

130"http://jsperf.com/localstoragevsmemory

3x faster

About the same

131"

How does this help maintainability?

132"

Makes future maintenance easier

133"

Makes future maintenance easier Prevent unexpected breakdowns

134"

topics.shift();!undefined"

135"

What is maintainability?

136"

It's about making our lives easier

137"

It's about making our work pass the test of time

Thank you!

138"

Yet Another Conference 2013

@jonbretman jonbretman.co.uk

Mobile Web Developer @ Badoo

http://techblog.badoo.com @BadooTech

http://habrahabr.ru/company/badoo

@BadooDev

top related