Kuba Niechcial
I am senior software developer and team leader at netguru, Poland. I work mostly with Ember.js, React and Ruby on Rails. I am passionate blogger and you can find out most of my work on my website.
Kuba Niechciał
Content
How does Ember.js work in the browser?
Event driven environment afterwards
Short setup phase on DOMContentLoaded event
keyUp, keyDown, click, mouseMove and others...
What is the reason of Ember Run Loop?
Performance
Batch similar actions
Reduce number of expensive actions
<div id="foo"></div>
<div id="bar"></div>
<div id="baz"></div>
foo.style.height = "500px" // write
foo.offsetHeight // read (recalculate style, layout, expensive!)
bar.style.height = "400px" // write
bar.offsetHeight // read (recalculate style, layout, expensive!)
baz.style.height = "200px" // write
baz.offsetHeight // read (recalculate style, layout, expensive!)
foo.style.height = "500px" // write
bar.style.height = "400px" // write
baz.style.height = "200px" // write
foo.offsetHeight // read (recalculate style, layout, expensive!)
bar.offsetHeight // read (fast since style and layout is already known)
baz.offsetHeight // read (fast since style and layout is already known)
{{user.firstName}}
{{user.fullName}}
user: Ember.Object.create({firstName:'Tom', lastName:'Huda'});
fullName: Ember.computed 'user.firstName', 'user.lastName', function() {
this.get('user.firstName') + ' ' + this.get('user.lastName');
});
user.set('firstName', 'Yehuda');
// {{firstName}} and {{fullName}} are updated
user.set('lastName', 'Katz');
// {{lastName}} and {{fullName}} are updated
What is Ember Run Loop?
Well, it's not a loop...
Run Loop aggregates changes over time and schedules them
Than executes them in some moment that probably would be optimal
How Ember Run Loop is triggered in the framework?
Ember listens to set of events on the level of top app element (mostly <body>)
On any event, Ember starts Run Loop and starts batching actions to execute
At the end of the handler code, the queues are flushed and the job is done
Ember Run Loop is based on queues
Ember.run.queues
["sync", "actions", "routerTransitions", "render", "afterRender", "destroy"]
What is the algorithm of execution?
What is the reason of fifth step?
Most used methods of Ember Run
Schedulers
Wrappers
default actions queue
Other
private Ember API
Let's take a look at couple of examples
Noisy Run Loop
Nested Run Loops
Going back to former queues
Example of using #sync
App = Ember.Application.create();
App.IndexController = Ember.Controller.extend({
actions: {
handleChange: function() {
// Ember.run.sync();
console.log(this.get("value"));
}
},
value: 0,
classNames: ["controller"]
});
App.SomeValueComponent = Ember.Component.extend({
valueChanged: function(val) {
this.set('value', val);
this.sendAction('valueChange');
},
didInsertElement: function() {
this.$("input").on("keyup", Ember.run.bind(this, function() {
this.valueChanged(this.$("input").val());
}));
},
classNames: ["component"]
});
Doesn't apply data-down-action-up
Example of using #debounce
Sometimes we need to handle some repeated events - like scrolling
Observers vs. computed properties
Which is executed first in Run Loop?
partOfNameChanged: Ember.observer("firstName", "lastName", function() {
console.log("[Observer]: Executing...");
})
fullName: Ember.computed("firstName", "lastName", function() {
console.log("[Computed property]: Executing...");
return (this.get("firstName") + " " + this.get("lastName"));
})
toggleName: function() {
this.set("firstName", "Foo");
this.set("lastName", "Bar");
}
How many times does it log?
partOfNameChanged: Ember.observer("firstName", "lastName", function() {
Ember.run.once(this, "doSomeProcessing");
})
doSomeProcessing: function() {
console.log("[Observer]: Executing...");
}
fullName: Ember.computed("firstName", "lastName", function() {
console.log("[Computed property]: Executing...");
return (this.get("firstName") + " " + this.get("lastName"));
})
toggleName: function() {
this.set("firstName", "Foo");
this.set("lastName", "Bar");
}
How many times does it log now?
When must I explicitly start
Ember Run Loop?
Ember Run Loop should be started explicitly in asynchronous callback (AJAX, custom event handlers, etc.)
this._select = this.$().select2(options);
// run ember bindings on after select2 `change` event
this._select.on("change", run.bind(this, function() {
var data = this._select.select2("data");
this.selectionChanged(data);
}));
Can I schedule jobs if Ember Run is not running?
$('a').click(function() {
console.log('Doing things...');
Ember.run.schedule('actions', this, function() {
// Do more things
});
});
Yes, I can, thanks to autoRun
Auto start Ember Run when scheduling
But... autoRun is switched off on testing
Testing with Ember Run Loop
Autoruns are Embers way of not punishing you in production if you forget to open a runloop before you schedule callbacks on it.
Some of Ember's test helpers are promises that wait for the run loop to empty before resolving. If your application has code that runs outside a runloop, these will resolve too early and give erroneous test failures which are difficult to find. Disabling autoruns help you identify these scenarios.
More to read and watch
Thanks guys!
By Kuba Niechcial
Presentation about Ember Run Loop - what it is, how it works and how to use it by @jniechcial at @netguru.
I am senior software developer and team leader at netguru, Poland. I work mostly with Ember.js, React and Ruby on Rails. I am passionate blogger and you can find out most of my work on my website.