Writing Fast Client-Side Code: Lessons Learned from SproutCore

85
SproutCore and Performance Wednesday, June 29, 2011

description

The SproutCore framework has evolved over the past five years to be an extremely high-performance framework that focuses on making it possible to build native-like applications in the browser.This means handling problems like working with extremely large data-sets, inconsistent connectivity, and complex DOMs. Lately, it has meant figuring out how to properly use new browser features that can make a big difference to perceived performance, like hardware acceleration.In this talk, Yehuda will cover some of the techniques that SproutCore has used historically to enable extremely complex applications to perform well in the browser, as well as what new technologies the team is looking at to leverage the latest browser technologies in building compelling content for the web.

Transcript of Writing Fast Client-Side Code: Lessons Learned from SproutCore

Page 1: Writing Fast Client-Side Code: Lessons Learned from SproutCore

SproutCore and Performance

Wednesday, June 29, 2011

Page 2: Writing Fast Client-Side Code: Lessons Learned from SproutCore

“Albert Einstein

One should not pursue goals that are easily achieved. One must develop an instinct for what one can just barely achieve through one’s greatest efforts.

Wednesday, June 29, 2011

Page 3: Writing Fast Client-Side Code: Lessons Learned from SproutCore

"Fast By Default"

Wednesday, June 29, 2011

Page 4: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Core Concepts

Wednesday, June 29, 2011

Page 5: Writing Fast Client-Side Code: Lessons Learned from SproutCore

1. JS is cheaper

than DOMWednesday, June 29, 2011

Page 6: Writing Fast Client-Side Code: Lessons Learned from SproutCore

2. Keep Intermediate State in JS

Wednesday, June 29, 2011

Page 7: Writing Fast Client-Side Code: Lessons Learned from SproutCore

(and out of DOM)

Wednesday, June 29, 2011

Page 8: Writing Fast Client-Side Code: Lessons Learned from SproutCore

3. Events Cannot

CoalesceWednesday, June 29, 2011

Page 9: Writing Fast Client-Side Code: Lessons Learned from SproutCore

(prefer cache

clearing)Wednesday, June 29, 2011

Page 10: Writing Fast Client-Side Code: Lessons Learned from SproutCore

4. Materialize Objects

When UsedWednesday, June 29, 2011

Page 11: Writing Fast Client-Side Code: Lessons Learned from SproutCore

(also, proxy, don't copy)

Wednesday, June 29, 2011

Page 12: Writing Fast Client-Side Code: Lessons Learned from SproutCore

5. Follow Speed

GuidelinesWednesday, June 29, 2011

Page 13: Writing Fast Client-Side Code: Lessons Learned from SproutCore

JS is Cheaper

than DOMWednesday, June 29, 2011

Page 14: Writing Fast Client-Side Code: Lessons Learned from SproutCore

change title

change name

change address

change DOM

change DOM

change DOM

Wednesday, June 29, 2011

Page 15: Writing Fast Client-Side Code: Lessons Learned from SproutCore

change title

change name

change address

change DOM

Wednesday, June 29, 2011

Page 16: Writing Fast Client-Side Code: Lessons Learned from SproutCore

change title

change name

change address

change DOM

Wednesday, June 29, 2011

Page 17: Writing Fast Client-Side Code: Lessons Learned from SproutCore

browsereventloop

SCrunloop

Wednesday, June 29, 2011

Page 18: Writing Fast Client-Side Code: Lessons Learned from SproutCore

nativeevent

handle event

handle event

handle event

sync bindings

Wednesday, June 29, 2011

Page 19: Writing Fast Client-Side Code: Lessons Learned from SproutCore

nativeevent

handle event

handle event

handle event

sync bindings

Wednesday, June 29, 2011

Page 20: Writing Fast Client-Side Code: Lessons Learned from SproutCore

nativeevent

handle event

handle event

handle event

sync bindings

Wednesday, June 29, 2011

Page 21: Writing Fast Client-Side Code: Lessons Learned from SproutCore

JS Code

JS Code

JS Code

Event Handling

...

DOM Code

Wednesday, June 29, 2011

Page 22: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Keep Intermediate State in JS

Wednesday, June 29, 2011

Page 23: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Case Study

Wednesday, June 29, 2011

Page 24: Writing Fast Client-Side Code: Lessons Learned from SproutCore

“ I want to have a view that displays the total number of items that are marked done.

I want to have a feature that can mark all remaining items done.

Wednesday, June 29, 2011

Page 25: Writing Fast Client-Side Code: Lessons Learned from SproutCore

What do you want to do?

4 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

Wednesday, June 29, 2011

Page 26: Writing Fast Client-Side Code: Lessons Learned from SproutCore

What do you want to do?

4 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

Wednesday, June 29, 2011

Page 27: Writing Fast Client-Side Code: Lessons Learned from SproutCore

What do you want to do?

3 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

Wednesday, June 29, 2011

Page 28: Writing Fast Client-Side Code: Lessons Learned from SproutCore

What do you want to do?

3 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

Wednesday, June 29, 2011

Page 29: Writing Fast Client-Side Code: Lessons Learned from SproutCore

What do you want to do?

3 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

✓✓

Wednesday, June 29, 2011

Page 30: Writing Fast Client-Side Code: Lessons Learned from SproutCore

What do you want to do?

0 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

✓✓✓✓

Wednesday, June 29, 2011

Page 31: Writing Fast Client-Side Code: Lessons Learned from SproutCore

"KVO"

Wednesday, June 29, 2011

Page 32: Writing Fast Client-Side Code: Lessons Learned from SproutCore

item marked done

re-render stats view

Wednesday, June 29, 2011

Page 33: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Backbone

window.AppView = Backbone.View.extend({  initialize: function() {    _.bindAll(this, 'addOne', 'addAll', 'render');    this.input    = this.$("#new-todo");    Todos.bind('add',     this.addOne);    Todos.bind('refresh', this.addAll);    Todos.bind('all',     this.render);    Todos.fetch();  },   render: function() {    var done = Todos.done().length;    this.$('#todo-stats').html(this.statsTemplate({      total:      Todos.length,      done:       Todos.done().length,      remaining:  Todos.remaining().length    }));  }});

Wednesday, June 29, 2011

Page 34: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Backbone

window.TodoList = Backbone.Collection.extend({  done: function() {    return this.filter(function(todo){      return todo.get('done');    });  },     remaining: function() {    return this.without.apply(this, this.done());  }}); window.Todos = new TodoList;

Wednesday, June 29, 2011

Page 35: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Toggling

Todos.forEach(function(todo) {  todo.toggle();});

Wednesday, June 29, 2011

Page 36: Writing Fast Client-Side Code: Lessons Learned from SproutCore

item marked done

compute remaining

compute done

render stats view

x N

Wednesday, June 29, 2011

Page 37: Writing Fast Client-Side Code: Lessons Learned from SproutCore

This is foundational

Wednesday, June 29, 2011

Page 38: Writing Fast Client-Side Code: Lessons Learned from SproutCore

No notion of intermediate

stateWednesday, June 29, 2011

Page 39: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Prefer Coalescing Operations

Wednesday, June 29, 2011

Page 40: Writing Fast Client-Side Code: Lessons Learned from SproutCore

SproutCore

ArrayController.create({  content: [],

  remaining: function() {    return this.filterProperty('isDone', false);  }.property('@each.isDone')});

Wednesday, June 29, 2011

Page 41: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Superficially Similar

Wednesday, June 29, 2011

Page 42: Writing Fast Client-Side Code: Lessons Learned from SproutCore

item marked done

clear remaining cache

compute remaining

render stats view

x N

run loop

intermediate state

Wednesday, June 29, 2011

Page 43: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Easy to Overlook

Wednesday, June 29, 2011

Page 44: Writing Fast Client-Side Code: Lessons Learned from SproutCore

SproutCore

ArrayController.create({  content: [],

  remaining: function() {    return this.filterProperty('isDone', false);  }.property('@each.isDone')});

Wednesday, June 29, 2011

Page 45: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Key:Declare Intent

Wednesday, June 29, 2011

Page 46: Writing Fast Client-Side Code: Lessons Learned from SproutCore

"Coalesce"

Wednesday, June 29, 2011

Page 47: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Wrong

Wednesday, June 29, 2011

Page 48: Writing Fast Client-Side Code: Lessons Learned from SproutCore

A

"hello"

B

"hello"

Wednesday, June 29, 2011

Page 49: Writing Fast Client-Side Code: Lessons Learned from SproutCore

A

"1"

B

"1"

Wednesday, June 29, 2011

Page 50: Writing Fast Client-Side Code: Lessons Learned from SproutCore

A

"12"

B

"12"

Wednesday, June 29, 2011

Page 51: Writing Fast Client-Side Code: Lessons Learned from SproutCore

A

"123"

B

"123"

Wednesday, June 29, 2011

Page 52: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Right

Wednesday, June 29, 2011

Page 53: Writing Fast Client-Side Code: Lessons Learned from SproutCore

A

"hello"

B

"hello"

Wednesday, June 29, 2011

Page 54: Writing Fast Client-Side Code: Lessons Learned from SproutCore

A

"1"

B

"hello"

Wednesday, June 29, 2011

Page 55: Writing Fast Client-Side Code: Lessons Learned from SproutCore

A

"12"

B

"hello"

Wednesday, June 29, 2011

Page 56: Writing Fast Client-Side Code: Lessons Learned from SproutCore

A

"123"

B

"hello"

Wednesday, June 29, 2011

Page 57: Writing Fast Client-Side Code: Lessons Learned from SproutCore

A

"123"

B

"hello"run loop

Wednesday, June 29, 2011

Page 58: Writing Fast Client-Side Code: Lessons Learned from SproutCore

A

"123"

B

"123"

Wednesday, June 29, 2011

Page 59: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Not 3 Deferred

ObserversWednesday, June 29, 2011

Page 60: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Materialize Objects

When UsedWednesday, June 29, 2011

Page 61: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Large JSON Structure

{  contacts: [    { name: "Yehuda", ... },    ... x 10,000  ]}

Wednesday, June 29, 2011

Page 62: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Acre, Julie

Appleseed, Johnny

Arrow, Bob

Astels, David

Atwood, Michael

Axelrod, Peter

Azeroth, Roy

Wednesday, June 29, 2011

Page 63: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Data Store

(JSON Hashes)

Contact

nametitleaddresstelephone

on demand

Wednesday, June 29, 2011

Page 64: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Data Store

(JSON Hashes)

Contacts

where company = "GOOGLE"

live

RecordArray

Ajax Response

Wednesday, June 29, 2011

Page 65: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Contact

datastatus

{ name: "yehuda" title: "Chief Technologist" address: "690 Spruce" telephone: "718.877.1325"}

Wednesday, June 29, 2011

Page 66: Writing Fast Client-Side Code: Lessons Learned from SproutCore

No Need to Copy

PropertiesWednesday, June 29, 2011

Page 67: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Again, Foundational

Wednesday, June 29, 2011

Page 68: Writing Fast Client-Side Code: Lessons Learned from SproutCore

One More Thing

Wednesday, June 29, 2011

Page 69: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Page Speed

Wednesday, June 29, 2011

Page 70: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Build Tools

Wednesday, June 29, 2011

Page 71: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Packed Files

Wednesday, June 29, 2011

Page 72: Writing Fast Client-Side Code: Lessons Learned from SproutCore

CDN: Versioned

URLsWednesday, June 29, 2011

Page 73: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Expires Header: Same

Wednesday, June 29, 2011

Page 74: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Stylesheets at the Top

Wednesday, June 29, 2011

Page 75: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Scripts at the Bottom

Wednesday, June 29, 2011

Page 76: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Simple Layout

Wednesday, June 29, 2011

Page 77: Writing Fast Client-Side Code: Lessons Learned from SproutCore

External JS and CSS

Wednesday, June 29, 2011

Page 78: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Minification

Wednesday, June 29, 2011

Page 79: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Easier said than done

Wednesday, June 29, 2011

Page 80: Writing Fast Client-Side Code: Lessons Learned from SproutCore

SproutCore 2.0

Wednesday, June 29, 2011

Page 81: Writing Fast Client-Side Code: Lessons Learned from SproutCore

OverallFile Size

Matters, but not as much as you think.

Wednesday, June 29, 2011

Page 82: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Modules w/ Declared

DepsWednesday, June 29, 2011

Page 83: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Lazy Loading Modules

Wednesday, June 29, 2011

Page 84: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Thank you.

Wednesday, June 29, 2011

Page 85: Writing Fast Client-Side Code: Lessons Learned from SproutCore

Questions

Wednesday, June 29, 2011