Brandon
Brandon

Reputation: 3130

Emberjs Updates/Observers/Run Loop

I have a controller which observes a property (array), and every time it changes, calls an expensive function on the server, then displays the result.

In the initial controller setup (in the route), I need to loop through the array and set some of the values - i.e.

something.forEach(function(el) { myArrayProperty.set(el.id, true); });

This is firing the observer on every loop through the forEach. How can I loop through the forEach, update all the elements, and THEN allow the Ember observer to fire?

I've tried scheduleOnce and Ember.run(function() {..}) but I can't quite seem to get it working.

Thanks!

Upvotes: 2

Views: 332

Answers (2)

bguiz
bguiz

Reputation: 28587

One way of tackling this problem is to throttle or debounce the expensive function(s) that observe the array.

See Ember.run.debounce

E.g. you have this now:

App.MyController = Ember.ArrayController.extend({
  myExpensiveObserver: function() {
    /* some expensive computations */
  }.observes('[email protected]'),
});

... and you change that to this instead:

App.MyController = Ember.ArrayController.extend({
  myExpensiveObserver: function() {
    Ember.run.debounce(this, this.myExpensiveObserverImpl, 300);
  }.observes('[email protected]'),
  myExpensiveObserverImpl: function() {
     /* some expensive computations */
  },
});

(replace 300 with the minumum interval you want between recomputations.)

There is a subtle difference between Ember.run.debounce and Ember.run.throttle, and you might prefer one of them over the other. However, from your description, it sounds like either one could fit the bill.

As pointed out by @kingpin2k, be careful with the function you pass in to debounce or throttle. It cannot be anonymous, as Ember will not be able to determine whether they were indeed the same each time it is invoked.

Upvotes: 2

Kingpin2k
Kingpin2k

Reputation: 47367

bguiz is totally right, throttle or debounce it. Throttling will allow it to run every x milliseconds, and debounce will block it from running until it hasn't run for x milliseconds. One small nuance that was missed in the other answer is the way Ember keeps track of the debounces/throttles is by the comparing the passed in function. So passing in an anonymous function each time will just keep firing without throttling/debouncing.

App.MyController = Ember.ArrayController.extend({
  myExpensiveObserver: function() {
    Ember.run.debounce(this, this.realWorker, 300);
  }.observes('[email protected]'),
  realWorker: function(){
    console.log("I'm working");
  },
  myExpensiveObserverThrottle: function() {
    Ember.run.throttle(this, this.realWorkerThrottle, 300);
  }.observes('[email protected]'),
  realWorkerThrottle: function(){
    console.log("I'm working");
  }
});

Example: http://emberjs.jsbin.com/cixawagi/1/edit

Upvotes: 1

Related Questions