7

In an Ember app, say you have an observer or a property that watches an array, like so:

topContributor: (function() {
  // ... loop over articles (hence slow) ...
}).property('articles.@each.author')

Updating the articles array, through ember-data for instance, repeatedly triggers the property function for a total of articles.length times.

Is there a way to collapse the updates into one lazy update when all the changes have finished and the runloop is flushed?

Jo Liss
  • 30,333
  • 19
  • 121
  • 170

1 Answers1

10

Thanks to @wagenet and @krisselden for the following pointers:

At the moment, while bindings are deferred (lazy), observers and by extension computed properties trigger immediately. In the future, they might become deferred as well.

In the meantime, you can use Ember.run.once as a workaround to schedule a deferred function call, which will be run only once. Computed properties, I suppose, can be easily turned into observers to follow the same pattern. Here is an example:

updateTopContributor: function() {
  // ... loop over articles (hence slow) ...
  this.set('topContributor', ...);
},

_updateTopContributorObserver: (function() {
  Ember.run.once(this, 'updateTopContributor');
}).observes('articles.@each.author')
Jo Liss
  • 30,333
  • 19
  • 121
  • 170
  • The `updateTopContributor` will be called one time by runloop, but what I don't understand, is how it matches the end of the changes ? I suppose that the `articles` array update takes more than one runloop right ? so `updateTopContributor` will be called multiple times... I probably miss something here, but I'd really understand the flow here. Could you explain me ? – sly7_7 Sep 18 '12 at 07:31
  • The end of the runloop happens when the event handling is done. So if an Ajax response comes in for the data store, then it goes update-update-update (triggering the observer repeatedly), and at the very end, before returning to the browser, it will flush the runloop. Conceptually, all of this is similar to deferring a call with `setTimeout(..., 1)`. You might find more info in the [Ember.run reference](http://emberjs.com/api/classes/Ember.run.html) and [this blog post](http://www.thesoftwaresimpleton.com/blog/2012/04/03/testing-ember-and-the-runloop/). – Jo Liss Sep 18 '12 at 14:44
  • Ok, so if I understand, the flow is runLoop1 starts -> ajax response -> schedule updateTopContributor -> end of ajax response -> runLoop1 end -> runLoop1 flushed -> runLoop2 starts -> updateTopContributor triggered -> runLoop2 ends. The first runloop is running while the ajax call has not returned ? – sly7_7 Sep 18 '12 at 15:45