Writing Fast Client-Side Code: Lessons Learned from SproutCore

Post on 18-May-2015

1.913 views 1 download

Tags:

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

SproutCore and Performance

Wednesday, June 29, 2011

“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

"Fast By Default"

Wednesday, June 29, 2011

Core Concepts

Wednesday, June 29, 2011

1. JS is cheaper

than DOMWednesday, June 29, 2011

2. Keep Intermediate State in JS

Wednesday, June 29, 2011

(and out of DOM)

Wednesday, June 29, 2011

3. Events Cannot

CoalesceWednesday, June 29, 2011

(prefer cache

clearing)Wednesday, June 29, 2011

4. Materialize Objects

When UsedWednesday, June 29, 2011

(also, proxy, don't copy)

Wednesday, June 29, 2011

5. Follow Speed

GuidelinesWednesday, June 29, 2011

JS is Cheaper

than DOMWednesday, June 29, 2011

change title

change name

change address

change DOM

change DOM

change DOM

Wednesday, June 29, 2011

change title

change name

change address

change DOM

Wednesday, June 29, 2011

change title

change name

change address

change DOM

Wednesday, June 29, 2011

browsereventloop

SCrunloop

Wednesday, June 29, 2011

nativeevent

handle event

handle event

handle event

sync bindings

Wednesday, June 29, 2011

nativeevent

handle event

handle event

handle event

sync bindings

Wednesday, June 29, 2011

nativeevent

handle event

handle event

handle event

sync bindings

Wednesday, June 29, 2011

JS Code

JS Code

JS Code

Event Handling

...

DOM Code

Wednesday, June 29, 2011

Keep Intermediate State in JS

Wednesday, June 29, 2011

Case Study

Wednesday, June 29, 2011

“ 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

What do you want to do?

4 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

Wednesday, June 29, 2011

What do you want to do?

4 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

Wednesday, June 29, 2011

What do you want to do?

3 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

Wednesday, June 29, 2011

What do you want to do?

3 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

Wednesday, June 29, 2011

What do you want to do?

3 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

✓✓

Wednesday, June 29, 2011

What do you want to do?

0 items remaining

Mark All Done

Wash dishes

Take out garbage

Make bed

Relax

✓✓✓✓

Wednesday, June 29, 2011

"KVO"

Wednesday, June 29, 2011

item marked done

re-render stats view

Wednesday, June 29, 2011

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

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

Toggling

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

Wednesday, June 29, 2011

item marked done

compute remaining

compute done

render stats view

x N

Wednesday, June 29, 2011

This is foundational

Wednesday, June 29, 2011

No notion of intermediate

stateWednesday, June 29, 2011

Prefer Coalescing Operations

Wednesday, June 29, 2011

SproutCore

ArrayController.create({  content: [],

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

Wednesday, June 29, 2011

Superficially Similar

Wednesday, June 29, 2011

item marked done

clear remaining cache

compute remaining

render stats view

x N

run loop

intermediate state

Wednesday, June 29, 2011

Easy to Overlook

Wednesday, June 29, 2011

SproutCore

ArrayController.create({  content: [],

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

Wednesday, June 29, 2011

Key:Declare Intent

Wednesday, June 29, 2011

"Coalesce"

Wednesday, June 29, 2011

Wrong

Wednesday, June 29, 2011

A

"hello"

B

"hello"

Wednesday, June 29, 2011

A

"1"

B

"1"

Wednesday, June 29, 2011

A

"12"

B

"12"

Wednesday, June 29, 2011

A

"123"

B

"123"

Wednesday, June 29, 2011

Right

Wednesday, June 29, 2011

A

"hello"

B

"hello"

Wednesday, June 29, 2011

A

"1"

B

"hello"

Wednesday, June 29, 2011

A

"12"

B

"hello"

Wednesday, June 29, 2011

A

"123"

B

"hello"

Wednesday, June 29, 2011

A

"123"

B

"hello"run loop

Wednesday, June 29, 2011

A

"123"

B

"123"

Wednesday, June 29, 2011

Not 3 Deferred

ObserversWednesday, June 29, 2011

Materialize Objects

When UsedWednesday, June 29, 2011

Large JSON Structure

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

Wednesday, June 29, 2011

Acre, Julie

Appleseed, Johnny

Arrow, Bob

Astels, David

Atwood, Michael

Axelrod, Peter

Azeroth, Roy

Wednesday, June 29, 2011

Data Store

(JSON Hashes)

Contact

nametitleaddresstelephone

on demand

Wednesday, June 29, 2011

Data Store

(JSON Hashes)

Contacts

where company = "GOOGLE"

live

RecordArray

Ajax Response

Wednesday, June 29, 2011

Contact

datastatus

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

Wednesday, June 29, 2011

No Need to Copy

PropertiesWednesday, June 29, 2011

Again, Foundational

Wednesday, June 29, 2011

One More Thing

Wednesday, June 29, 2011

Page Speed

Wednesday, June 29, 2011

Build Tools

Wednesday, June 29, 2011

Packed Files

Wednesday, June 29, 2011

CDN: Versioned

URLsWednesday, June 29, 2011

Expires Header: Same

Wednesday, June 29, 2011

Stylesheets at the Top

Wednesday, June 29, 2011

Scripts at the Bottom

Wednesday, June 29, 2011

Simple Layout

Wednesday, June 29, 2011

External JS and CSS

Wednesday, June 29, 2011

Minification

Wednesday, June 29, 2011

Easier said than done

Wednesday, June 29, 2011

SproutCore 2.0

Wednesday, June 29, 2011

OverallFile Size

Matters, but not as much as you think.

Wednesday, June 29, 2011

Modules w/ Declared

DepsWednesday, June 29, 2011

Lazy Loading Modules

Wednesday, June 29, 2011

Thank you.

Wednesday, June 29, 2011

Questions

Wednesday, June 29, 2011