Understanding the Ember run loop

All of the Ember.js internal code, and most of the stuff you write while creating an Ember.js app runs with the help of the run loop. It is used to batch, order and reorder jobs in a way that is optimised for efficiency. I didn’t notice it’s existence before I ran into problems with the JavaScript setTimeout function callbacks and when manually running async calls to the API.

How Ember run loop works

If you’ve read any of the productivity books out there, they all state that batching similar jobs is the key to success. Ember run loop works in a similar way. By running same or similar jobs at the same time, the browser doesn’t have to skip around from task to task, which eases the burden on it, and if you change the same property a couple of times in the same loop cycle, it will only have to process the last change.

Jobs or tasks are scheduled into different queues, and the queues are processed by priority until they are empty.

Queues

Ember run loop consists of six queues

Ember.run.queues
// => ["sync", "actions", "routerTransitions", "render", "afterRender", "destroy"]

Each one of these queues is responsible for some jobs batch that runs inside of it.

  • sync contains the binding synchronisation
  • actions is the general work queue, and the one that generally handles promises.
  • routerTranisitions contains transition jobs in the router
  • render contains the jobs that are associated with rendering the page and updating the DOM
  • afterRender runs after the DOM is complete, after all the render jobs have been executed. This is the perfect place if you want to update the DOM after it has been rendered.
  • destroy is responsible for destroying everything other objects or jobs have scheduled to destroy.

Testing

Ember run loop is really important when running tests in Ember. Ember raises errors in testing mode when we try to schedule work without the run loop.

When should you use the run loop

Strictly speaking, all non Ember api code should be wrapped inside an Ember run loop. That includes:

  • AJAX callbacks
  • DOM updates and event callbacks
  • Websocket callbacks
  • setTimeout and setInterval callbacks
  • postMessage and messageChannel event handlers

Be sure to wrap the callback body in the ember run loop and not the whole invocation. For example:

var controller = this;
socket.on('channel', function (data) {
  Ember.run(controller, function() {
    console.log(data);
    this.set(‘message’, data.message);
  });
});

This fires an Ember run loop after the callback is executed, and the callback code will be executed at exactly the right moment.

Dynamic components in Ember.js

When building Ember.js apps you will try to avoid code duplication as much as possible. One of the ways of doing that is using Ember components. Components are small, reusable pieces of code, that share a common functionality. For example, you can have a component that shows a user’s Twitter feed, that receives the twitter handle as a parameter.

Components are the new hotness and the way to go with Ember.js 2.0 and they are also being introduced and used in HTML5. Ember components are closely built to adhere to the W3C specification so they should be compatible when the component adoption increases.

Sometimes you want to render a different component in the same place, for example a user’s image and contact info, which can be different for a person and an organisation. So to avoid ugly conditionals in handlebars code there is an option to show components dynamically with the convenient component helper.

You won’t avoid having those conditionals of course, but you won’t have to put them in your handlebars templates, which should be as logic-less as possible. They can reside at the model level, as a computed property. I will simplify this even further and use an example where we will receive the value from our API.

We will be using a simple polymorphic relationship in our API and values returned from ownerType will be “user” and “company” for this example.

Of course we want to show different data for the user and the company, but because we are showing them in the same place, we would have to use a conditional in handlebars to show them. And or model (or controller) should return the isUser boolean. This approach will make future code maintenance a nightmare.

// app/models/owner.js
import DS from 'ember-data';
import Ember from 'ember';

export default DS.Model.Extend({
  name: DS.attr('string'),
  ownerType: DS.attr('string'),
  // ...
  isUser: Ember.computed.equal('ownerType', 'User'),
  // ...
});
{{#if model.isUser}}
  {{owner/user-widget owner=model}}
{{else}}
  {{owner/company-widget owner=model}}
{{/if}}

As you can see, this conditional isn’t really the best one imaginable. If we add another ownerType possibility, we will have to add an additional component (which is the only thing we should be doing), add another boolean on the Owner model, and make the conditional above even more complex than it is. No one probably wants to be remembered by code like this:

{{#if model.isUser}}
  {{owner/user-widget owner=model}}
{{else}}
  {{#if model.isOrganisation}}
    {{owner/organisation-widget owner=model}}
  {{else}}
    {{owner/company-widget owner=model}}
  {{/if}
{{/if}}

There clearly must be a better and cleaner approach. Ember component helper comes to the rescue. And with some clean coding we can avoid all of the conditionals mentioned here.

// app/models/user.js
// ... 
   widgetComponentName: Ember.computed('ownerType', function() {
     return `owner/${this.get('ownerType').toLowerCase()}-widget`;
   });
// ...

This way, the model returns a convenient and usable string when we get the displayComponentName property from it. Now we can use this and have the cleanest possible handlebars template:

{{component model.widgetComponentName owner=model}}

Component helper will resolve the correct component and render it. If a new owner type pops up, the only thing we need to change is to add the widget component for that owner, which is also a great example of separation of concerns, and we are reducing code churn a lot. To reduce the code duplication and complexity you can also take use inheritance to combine similar functionality under one object, and extend it with specific code for each object. I’ve written a blog post about it called Simple Inheritance with Ember.js that you should definitely check out.

Simple inheritance with Ember.js

When doing Object-oriented programming, we are always seeking ways to reduce the duplication in the code we write. Reusing existing code is something that every programmer wants to do most of the time. Because, we have to admit it, we are pretty lazy. But that laziness brings us great stuff like frameworks we use in our everyday jobs.

Using Ember.js and ember-cli of course, there is an easy way to remove code duplication. Ember.js has a nice way to extend every existing class, you are already programming apps in Ember that way, by extending Ember.Route, Ember.Component, Ember.Controller and a lot of other stuff in the framework.

Realising this nice thing will help us on our way of achieving maximum code reuse. Let’s say we have a component bird

// app/components/my-bird.js
import Ember from 'ember';

export default Ember.Component.extend({
  name: 'Birdie McBird',
  actions: {
    fly: function() {
      alert("I'm flying, la la");
    },
    speak: function() {
      alert('Tweet');
    }
  }
});

And we want to implement some of the same actions in the duck component, because all ducks can fly, but they just sound different, so we would do it like this:

// app/components/my-duck.js
import MyBirdComponent from 'my-bird';

export default MyBirdComponent.extend({
  name: 'Ducky McQuack',
  actions: {
    speak: function() {
      alert('Quack!');
    },
    waddle: function() {
      alert('Waddle waddle!');
    }
  }
});

Of course, we have to define our templates, and link the actions inside them, so here it goes:

<!-- app/templates/components/my-bird.hbs -->
<h2>Hello, my name is {{name}}!</h2>
<button {{action 'speak'}}>Make a sound</button>
<button {{action 'fly'}}>Fly birdie fly</button>

<!-- app/templates/components/my-duck.hbs -->
<h2>Hello, my name is {{name}}!</h2>
<button {{action 'speak'}}>Make a sound</button>
<button {{action 'fly'}}>Fly birdie fly</button>
<button {{action 'waddle'}}>Make a move, duck</button>

<!-- app/templates/application.hbs -->
{{my-bird}}
<br>
{{my-duck}}

In Ember 2.0 you will be able to reference components with the angle bracket notation, just like any other regular html tag. I’ll write about those new features sometime in the future.

If you run the example, you see that we are reusing the speak method and redefining everything else, which is great. This is a really simplified example, and done with a component. You can do the same thing with controllers, models, even routes.

I’ve made a small demo on JSFiddle so you can try for yourself. Of course, it’s a globals based Ember app, but it’s the same principle as described here. And because ember-cli is the default way of developing Ember.js apps nowadays, I’ll keep my ember posts using it.

Notify an Ember.js app that a deployment has happened

The approach with refreshing regular web applications after deployment is pretty straightforward, you click on a link, it goes to the server, server renders a page. If the deployment has happened in the meantime, server renders you the current(new) version of the page. The issue with Ember.js is a pretty nice example of how the old approach doesn’t work anymore. You get the whole application when you first request the page, then everything happens in the browser. The only thing that goes between server and the client is the JSON being passed here and there.

Luckily we are already using Sam Saffron’s awesome gem message_bus, to notify the front-end that an update has happened in a model we are working on. So I decided to implement deployment notification using a similar approach.

First, we want to be able for the Ember app to know that a deployment has happened, so registering MessageBus and subscribing it to a channel is the first thing we will do. We chose the ApplicationController for this in Ember, because it is always loaded, regardless of the route. We are using ember-cli-growl component to provide us with growl like notifications, so you might need to adapt the code to suit your needs.

/* global MessageBus */
import Ember from 'ember';

export default Ember.Controller.extend({
  initMessageBus: function() {
   MessageBus.start();
   MessageBus.callbackInterval = 50;
  },
  subscribe: function() {
    var channel = '/deployment';
    var controller = this;
    MessageBus.subscribe(channel, function() {
      controller.growl.info('A new application version has been deployed, please reload the browser page.', { clickToDismiss: true });
    });
  },
  init: function() {
   this._super();
   this.initMessageBus();
   this.subscribe();
  }
});

In Rails, include the message_bus gem in the Gemfile, bundle install and run the console. Now you can try running MessageBus.publish('/deployment', 'foo') and you should see a notification pop up in your ember app. Ok, but we need to be able to call it somehow, and what better way to do it than using Rake.

desc "notifies Ember that a deploy has happened"
task notify_ember: :environment
  MessageBus.publish('/deployment', '')
end

Now you only have to call that task on the server when your deployment has finished and everything will be fine and dandy. There are a lot of options to do this, depending of your deployment strategies, and infrastructure. We are using Capistrano, so a nice after hook, running after the app server has restarted did the job quite well. If you are having trouble setting it up, feel free to ping me in the contact form.

ember-cli 101 Book Review

Ever since I first heard of Ember.js (even before the 1.0 days), I’ve been wanting to learn it. But the learning curve of the framework always veered me off from it. Also, the lack of a real project to apply Ember.js to it was also an issue. Yes, we can rebuild the Hello World (Todo MVC app) in any possible framework, but the real learning comes when you start building a real application, with all the issues and edge cases it brings with itself. Although I’ve read a lot of blog posts, watched a lot of screencasts, tinkered with it, and nothing came close to the information provided in the ember-cli 101 book by Adolfo Builes. As ember-cli is now the official “Ember Way” (not to be confused with the book that is coming out in spring/summer 2015), I’ve realised it’s worth learning about, and using it to build great applications.
A warning note, if you are looking into Ember.js, and aren’t really that proficient with JavaScript, do yourself a favour and go read this four book series first: Master Space and Time With JavaScript by Noel Rappin. It will teach you the basics of JavaScript, and it also contains an Ember.js book as the last part of the book series.
In the book, the author guides us through creating a simple item borrowing app. The difference from all other tutorials is that the author has created the backend API for us and has different endpoints, as he guides us through the book. You will learn how to implement a medium complexity app with a REST (Rails active_model_serializers) API. Also, you will touch all of the Ember.js components, and implement them in your demo application. You will also get to learn the awesome ember-cli cli generators, which are a really nice thing, especially looking from a perspective of a Ruby/Rails developer, that is used to having those nice things.
Although I’ve learned a lot from this book, I still have to reference the Ember.js API docs for every complex issue. As I will probably have another blog post on learning things, I won’t write much of it now, but the gist is, you have to build 10 apps to be a specialist in a framework, or one or two really nasty ones. You will encounter basic issues when you are starting out, and some weird ones specific only to your project. But that is the thrill of our job, and we need to embrace it, it wouldn’t be much fun writing todo apps our whole lives, would it?
Back to the book, it’s a fairly light read, updates constantly, and as the author himself promised, it will be updated at least until Ember.js version 2.0, which is still in the RFC process. If you are thinking about learning Ember.js, you should definitely consider reading it. You won’t learn everything, it isn’t a silver bullet book that will teach you a new framework in an afternoon, but it will give you a much better start, compared to everything else that is out there. Also, consider that Ember.js is constantly improving(with a 6-week release cycle), so having an up to date resource, while you are learning the framework is a great thing.