Search code examples
ember.jsrsvp.js

How to register a custom callback after Ember.RSVP.hash


I have a route that pulls in 2 different promises using RSVP like so

model: function() {
  return Ember.RSVP.hash(function() {
    stuff: App.Thing.find(),
    other: this.store.find('appointments', {day: day})    
  });
}

The challenge is that I have a custom function I bind/invoke in the "then" of the 2nd promise shown above. How can I invoke this when the callback happens along side another promise using RSVP?

Here is the custom callback as it stands today (not inside of RSVP.hash just yet)

    function bindContextAndGenerateAvailable(employee, other, appointments) {
        return function(filteredAppointments) {
            //will take the filtered collection and do something w/ it
            //to populate the bound appointments array passed in
        }
    }

    var appointments = Ember.A([]);
    this.store.find('appointment', {day: day}).then(function(response) {
        Ember.RSVP.all(response.getEach('employee')).then(function(empls){
          var filtered = response.filterBy('employee.id', employee);
          Ember.RSVP.resolve(filtered).then(bindContextAndGenerateAvailable(employee, other, appointments));
        });
    });
    return appointments;

Solution

  • Okay, I'm not sure if I completely understand, but I'm going to take a stab at it, and if I'm wrong I'll just quickly edit as you say my guessing is wrong.

    Promises are super awesome when you do chaining of them (.then). Let me see if I can do some quick examples and see if this applies to what you're doing.

    Chaining returns the last result.

    var foo = new Ember.RSVP.Promise(function(resolve){
      resolve(1);
    }).then(function(result){
      return result + 2;
    });
    
    foo.then(function(result){
      alert(result); // this will alert 3, not 1
    });
    

    http://emberjs.jsbin.com/levoyama/1/edit

    Chaining returns the deepest result. If you return a promise as the result of the then, it waits on that to resolve, and returns the result of it. Quick note: cast is a quick way to cast anything into a promise, making it thenable.

    var bar = Ember.RSVP.Promise.cast(1).then(function(result){
      return new Ember.RSVP.Promise(function(resolve){
        resolve(2 + result);
      });
    });
    
    bar.then(function(result){
      alert(result); // this will alert 3, not 1
    });
    

    http://emberjs.jsbin.com/voxevucu/1/edit

    Hash taking the latest and greatest

    Hash is going to take the deepest/last result of any promise sent to it, and use the result of that in its resultant hash. In the example below, both promise 1 and promise 2 will result in 5, despite their initial promise values being 1/2.

    var promise1 = Em.RSVP.Promise.cast(1)
                     .then(function(result){ return result + 1; })
                     .then(function(result){ return result + 1; })
                     .then(function(result){ return result + 1; })
                     .then(function(result){ return result + 1; });
    
    var promise2 = Em.RSVP.Promise.cast(2)
                     .then(function(result){
                      return new Ember.RSVP.Promise(function(resolve){
                        resolve(result + 3);
                      });
                     });
               
    
    var hash = Em.RSVP.hash({
       p1: promise1,
       p2: promise2
    });
    
    hash.then(function(result){
      alert(result.p1 + ' + ' + result.p2 + ' = ' + (result.p1 + result.p2) + ', alert the presses!!!!');
    });
    

    http://emberjs.jsbin.com/vevaruta/1/edit

    Sharing promises/multiple observers

    I reread the question and have another guess. Promises can have infinite number of observes that will all fire when the promise is resolved, if you need to use a promise for two different purposes.

    var promise1 = Em.RSVP.Promise.cast('of warcraft');
    
    promise1.then(function(result){
      alert('hello world ' + result);
    });
    
    promise1.then(function(result){
      alert('stop playing world ' + result);
    });
    
    Em.RSVP.hash({
      p: promise1
    }).then(function(hash){
      alert('hash result p is: ' + hash.p);
    });
    

    http://emberjs.jsbin.com/sovolibo/1/edit

    In the scenario where you want the result (for the model) to be modified after both promises were resolved you would do something like this.

    model: function(){
      var promise1 = Ember.RSVP.Promise.cast(1);
      var promise2 = Ember.RSVP.Promise.cast(2);
    
      return Ember.RSVP.hash({
        p1 = promise1,
        p2 = promise2
      }).then(function(result){
          return result.p1 + result.p2;
      });
    }
    

    The result of the model ends up being 3, not a hash, cause we did some post processing with the resultant of the hash.

    But if you want to do something async, as in it doesn't matter for the model's sake, it would be something like this:

    model: function(){
      var promise1 = Ember.RSVP.Promise.cast(1);
      var promise2 = Ember.RSVP.Promise.cast(2);
    
      var hash = Ember.RSVP.hash({
        p1 = promise1,
        p2 = promise2
      });
      
      var randomPromise = hash.then(function(result){
        return result.p1 + result.p2;
      });
    
      randomPromise.then(function(result){
        alert(result);
      });
    
      return hash;
    }
    

    In this scenario, the model hook needs the hash, but then you want to do something different with the results when it's finished, and the model hook doesn't need to wait on the random promise after the fact.