hesson
hesson

Reputation: 1862

How to defer a call in Backbone on completion of several asynchronous calls?

If I have a backbone collection that has a method that calls an asynchronous method on each of its models like this:


getStatus: function() {
  this.each(function(model) {
    model.getStatus();
  });
}

And in the model class, an asynchronous ajax call is made like this:


getStatus: function() {
  $.ajax({
    //ajax properties here
  });
}

How can I determine when each and every model has completed it's asynchronous call (not necessarily successfully) and returned?

So in my collection, I need a getStatusSuccess method that executes after all these asynchronous calls have been completed. I have looked into jQuery deferreds, and I have tried a few things to get it to work, but to no avail. However, I still believe that it can be solved using deferreds.

Upvotes: 1

Views: 176

Answers (3)

JuliaCesar
JuliaCesar

Reputation: 1029

Can suggest two ways to defer a call:

  1. jQuery $.when() construction, which is perfectly described above by nikoshr
  2. or Underscore _.after(count, function) method, which takes basically two arguments: amount of asynchronous calls and your call to defer.

Upvotes: 0

nikoshr
nikoshr

Reputation: 33364

  • $.ajax returns a Deferred object
  • you can combine Deferred objects with jQuery.when to produce a "master" Deferred

    In the case where multiple Deferred objects are passed to jQuery.when, the method returns the Promise from a new "master" Deferred object that tracks the aggregate state of all the Deferreds it has been passed.
    The method will resolve its master Deferred as soon as all the Deferreds resolve, or reject the master Deferred as soon as one of the Deferreds is rejected.

  • Backbone proxies a lot of functions from Underscore on collections, notably _.invoke which returns an array with the results of the calls

  • function.apply will let you call a function with a given context and arguments provided as an array

Combining all this :

var M = Backbone.Model.extend({
    getStatus: function() {
        return $.ajax({
            // ...
        });
    }
});
var C = Backbone.Collection.extend({
    model: M,
    getStatus: function() {
        var jqXHRs = this.invoke('getStatus');
        return $.when.apply(this, jqXHRs);
    }
});

var c = new C([
    {id: 1},
    {id: 2}
]);
c.getStatus().always(function() {
    console.log('done');
});

And a demo http://jsfiddle.net/nKDjW/

Upvotes: 2

Poni
Poni

Reputation: 11337

Check my recent answer at Sequence of operation in Node.js.

Basically you could use Async.js. Check its parallel function..

Upvotes: 0

Related Questions