Overview

Topics:

  • what a Run Loop is?
  • Why a Run Loop
  • Run Loop Queues in Ember
  • autoRun
  • autoRun and Testing
  • Other methods of Ember.run

what a Run Loop is?

what?

... not a loop like programmers might think

for (i = 0; i < length; i++) {
  // some stuff here
}

It is an 'aggregate changes over time' mechanism.

what?

..used to batch, and order (or reorder) work in a way that is most ... efficient ... by scheduling work on specific queues. These queues have a priority, and are processed to completion in priority order.

what?

Queues of work to be done

Queues are like buckets Queues are like buckets Queues are like buckets Queues are like buckets Queues are like buckets Queues are like buckets

Queues are run in order of priority

Why a Run Loop?

why?

Some things 'cost' more than others

  • DOM manipulation
  • layout calculations
  • your cool, but expensive algorithm

why?

Ineffective use of DOM calculations / layout

// assuming divs foo, bar, baz foo.style.height = "500px"; foo.offsetHeight;

bar.style.height = "400px"; foo.offsetHeight;

baz.style.height = "200px"; foo.offsetHeight;

why?

Ineffective use of DOM calculations / layout

// assuming divs foo, bar, baz foo.style.height = "500px"; // write foo.offsetHeight; // read (recalculate style, layout)

bar.style.height = "400px"; // write foo.offsetHeight; // read (recalculate style, layout)

baz.style.height = "200px"; // write foo.offsetHeight; // read (recalculate style, layout)

why?

Grouping writes before reads helps


// assuming divs foo, bar, baz
foo.style.height = "500px"; // write
bar.style.height = "400px"; // write
baz.style.height = "200px"; // write

foo.offsetHeight; // read (recalculate style, layout)
bar.offsetHeight; // read (style and layout is already known)
baz.offsetHeight; // read (style and layout is already known)

why?

var Meetup = Ember.Object.extend({
  title: 'Ember.js',
  location: 'SLC',
  food: 'pizza',
  prettyTitle: function() {
    return this.get('title') + ' - ' + this.get('location');
  }.property('title', 'location');
});
  {{location}}
  {{prettyTitle}}

why?

var Meetup = Ember.Object.extend({
  title: 'Ember.js',
  location: 'SLC',
  food: 'pizza',
  prettyTitle: function() {
    return this.get('title') + ' - ' + this.get('location');
  }.property('title', 'location');
});
  var meetup = Meetup.create();
  meetup.set('location', 'PDX');
  meetup.set('title', 'Emberenos');

why?

without the run loop

  var meetup = Meetup.create();
  meetup.set('location', 'PDX'); // {{location}} and {{prettyTitle}} updated
  meetup.set('title', 'Emberenos'); // {{title}} and {{prettyTitle}} updated

why?

with the run loop

  var meetup = Meetup.create();
  meetup.set('location', 'PDX');
  meetup.set('title', 'Emberenos');
  // {{location}}, {{title}} and {{prettyTitle}} updated

why?

aggregate = net zero change

  var meetup = Meetup.create();
  meetup.set('location', 'PDX');
  meetup.set('title', 'Emberenos');

  meetup.set('location', 'SLC');
  meetup.set('title', 'Ember.js');

  // no DOM update

Run Loop Queues in Ember

queues

  Ember.run.queues
  • sync: synchonization jobs, propagate bound data
  • actions: general work queue, scheduled tasks, promises, etc
  • routerTransitions: routing transition jobs
  • render: jobs meant for rendering, typically will update the DOM
  • afterRender: after the render is complete
  • destroy: jobs to finish tear-down objects other jobs have destroyed

psuedo algorithm

Queues are like buckets Queues are like buckets Queues are like buckets Queues are like buckets Queues are like buckets Queues are like buckets

psuedo algorithm

how the run loop processes jobs

  • if no queues with jobs, return -- done
  • first QUEUE with pending jobs = CURRENT_QUEUE
  • build temp WORK_QUEUE
  • pull CURRENT_QUEUE into WORK_QUEUE
  • process jobs one at a time in WORK_QUEUE
  • repeat

psuedo algorithm

how the run loop processes jobs

Queues are like buckets Queues are like buckets Queues are like buckets Queues are like buckets Queues are like buckets Queues are like buckets

autoRun

autoRun

In development and production Ember will automatically wrap code it finds in an autoRun when appropriate

  doSomething: function() {
    this.set('propA', 3);
    this.set('propB', 4);
  }
  doSomething: function() {
    Ember.run.begin();
    this.set('propA', 3);
    this.set('propB', 4);
    nextTick(function(){
      Ember.run.end();
    });
  }

autoRun

wrap your async

  doSomething: function() {
    Ember.run(function() {
      this.set('propA', 3);
      this.set('propB', 4);
    });
  }

potential situations to consider

  • $.ajax callbacks
  • animation complete handler
  • setTimeout
  • setInterval
  • postMessage
  • MessageChannel
  • jQuery event handling
  • websocket

Generally anything async that you write should consider the run loop.

autoRun and Testing

autoRun and Testing

Ember testing mode disables autoRun

Can cause testing issues if you are unaware of autoRun

Other `Ember.run` methods

Ember.run stuff

  • Ember.run.join
  • Ember.run.later <- use instead of setTimeout
  • Ember.run.next <- next tick, consider schedule
  • Ember.run.schedule <- push to queue
  • Ember.run.throttle

plus more in Ember docs

Other Resources

</presentation>

thanks!