MVC Performance
Ember.js
Standa Opichal
@opichals
MVC
Server Client
ViewControllerModel HTML
Single Page App MVC
Server Client
VCM HTMLVCM ?
SPA Load Performance
VCM HTML?
JS
VCM
ClientServer
Client MVC Performance
ViewControllerModel
Runtime Performance
Expressiveness (Clarity + Brevity)
Performance Conscious Concepts
Framework Performance
Instance Construction
Eventing
Key-Value Observing
Runtime Performance
View
Controller
Model
JavaScript
var brendan = {
name: ‘Brendan’
};
Performance: very fast
KVO: not really
Construction
Object
var eric = new Y.Base({
name: ‘Eric’
})
var tom = Ember.Object.create({
name: ‘Tom’
})
Construction: KVO
KVO
var tom = Ember.Object.create({
name: ‘Tom’
_nameDidChange: function() {
}.observes(‘name’)
firstName: function() {
}.property(‘name’)
})
Construction: KVO
KVO
for (var i=0; i<10000; i++) {
constructSingleKVO();
}
Synchronous
Blocks browser event loop till finished
Is it fast enough?
Construction Performance
KVO
Expected Construction Performance
Time
Loopcount
Expectation
KVO
Construction Performance WTF
Time
Loopcount
Reality
Synchronous for loop!?
WTF?
GC
View
Controller
Model
Lifecycle Events
Initializing
Destroying
KVO Book Keeping
Observers
Varies significantly with JSVM, Browser, OS
Construction Performance Summary
View
Controller
Model
Eventing
Barebone eventing in
YUI vs Ember.js
Eventing: YUI
kvo.fire(‘export’, { report: item })
kvo.on(‘export’, function onExport(e) {
e.report.focus(); // facade
e.preventDefault(); // DOM-like
e.stop();
});
kvo.after(‘export’, function afterExport(e) {
e.report.loseFocus();
});
Eventing: Ember.js
controller.send(‘export’, { report: item })
// route action
export: function onExport(args) {
args.report.focus(); // facade
}
Eventing Performance
Facading, DOM-like events, default actions
-> Lots of throwaway instances
-> frequent GC events
Simple method calls win!
YUI
keyChange DOM-like Events
Ember.js
Declarative Observer Notation
Eventing is not used
KVO
Ember.Object.create({
name: ‘Tom’,
content: Em.Object.create({ name: ‘Jerry’ }),
nameDidChange: function() {
// this runs upon name change
}.observes(‘name’, ‘content.name’)
});
Ember.js Observers
Ember.js wins
Observers do by design way less
work to function
+ Declarative is also readable
KVO Performance
Expressiveness
Templates
Live Bindings
Dependency Injection
Ember.js Expressiveness
App.UserController = Ember.ObjectController.extend({
content: Em.Object.create({
name: ‘Tom’
});
firstNameBinding: ‘content.name’
});
user-template:
User: {{firstName}}
Performance Conscious Design
On-Demand
Async
Ember.js wins
Observers do by design way less
work to function
+ Declarative is also readable
Example: GoodData Dashboard
Server Data
var tab = {
items: [ // items.length ~ 100
{ type: ‘filter’ },
{ type: ‘report’ },
{ type: ‘line’ },
...
]
}
Dashboard Model
Tab = Em.Object.extend({ // KVO
items: Array<TabItem>
})
TabItem = Em.Object.extend({
type: ...
})
Materialization
Server Data -> Model Instances
var tab = Tab.create(tabData)
var items = tab.get(‘items’);
tabData.items.forEach(function(item) {
items.push(TabItem.create(item))
})
Slow: Dashboard ~ 10 Tabs * 100 items
// Want no TabItem instances created at first
var tab = Tab.create({tabData: tabData});
// On-demand TabItem creation
tab.get(‘items’);
Lazy Materialization FTW
Tab = Em.Object.extend({
tabData: {...}
items: function() {
return this.get(‘tabData’).items.map(function(item) {
return TabItem.create(item);
})
}.property(‘tabData’),
})
Lazy Materialization
Tab = Em.Object.extend({
tabData: {...}
items: function() {
...
}.property(‘tabData’),
_itemsDidChange: function() {
var types = this.get(‘items’).filter(...);
// does stuff every items/tabData change
}.observes(‘items’); // gets ‘items’ on Tab creation
})
Does it work?
Tab = Em.Object.extend({
tabData: {...}
items: function() { … }.property(‘tabData’),
init: function () {
set(‘tabData’, {});
// not declarative, unclear why, ugly
// -> sooner or later somebody
// _will_ forget and refactor to declarative
this.addObserver(‘items’, this._itemsDidChange);
}
});
Ugly on-demand addObserver
Tab = Em.Object.extend({
items: function() { … }.property(‘tabData’),
_itemsDidChange: function() {
var types = this.get(‘items’).filter(...);
}.observes(‘items’);
});
Observers are initialized after the ‘items’ computed property
materialization (a tab.get(‘items’) call)
Since Ember.js 1.0-rc8
Use of Object.observe()
Would make observing async
Current Chrome Canary
In Ember 2.0 (?)
Performance Future
Thank You!
MVC Performance, Ember.js

MVC Performance, Ember.js