Pergunta

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;
Foi útil?

Solução

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.

Outras dicas

The answer above is extrememly helpful. I simply want to chime in with an alternate example for resolving:

var promise, colors = ['red', 'yellow', 'blue'];

promise = new Ember.RSVP.Promise(function(resolve, reject) {

  // timeouts below mimic a webservice response with new data
  setTimeout(function() {
    colors.pushObject('orange');
  }, 1000);

  setTimeout(function() {
    colors.pushObject('green');
  }, 2000);

  Ember.run.later(colors, function() {
    colors.pushObject('pink');
  }, 3000);

  resolve(colors);
});

return promise;

This would immediately render the values 'red', 'yellow' and 'blue' and over the next three seconds render 'orange', then 'green', and finally 'pink'. Hopefully this isn't too redundant.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top