Series: ESNext

Multiple Concurrent Promises

Published on Nov 27, 2015

Sometimes promises have to happen in an exact order, but often there will be several calls that can be made concurrently. RSVP’s Promise implementation allows that.

In this video we show how to use the hash method, one of several methods available to do concurrent promises.


Links

Code

We can use .hash() to wait on multiple promises and put them within an object.

  model(){
    return new Ember.RSVP.hash({
        worlds: this.store.findAll('world'),
        monsters: this.store.findAll('monster'),
        taco: true
    }).then((response)=>{
      console.log('the response was', response)
      return response
    }).catch((reason)=>{
      console.log("rejected", reason)
    })
  }

.all() can be used to do the same thing but put the promises in an array.

Transcript

So we’ve been talking about promises and how they’re useful for your app, but so far we’ve only done single promises, basically acting in sequence. But there’s a whole 'nother world where you can do multiple promises through methods like hash or all. We’ll look into those today.

So we have our Monster Card program, and for this route we’re pulling in a lot of monsters. We’re using the Ember data findAll method. And as you recall, findAll is a promise, and model has stuff to deal with promises.

But what if we need to find more than just monsters? What if we need to find all the worlds that are in this game? Now if this were a purely synchronous thing, then we would be able to just put them in a hash and then have them as keys on that hash. However, even if we made it so that it was a promise so it worked, it would still have problems in high latency situations. Notice how it took a few seconds for that to load. That’s because the page was already loading before these promises were loaded, because Ember doesn’t recognize these as promises in its loading machinery. It only looks at this. And this is fine for what we’re doing here, but in more complex applications that could be a problem.

So instead, you can do a hash. And so using an Ember.RSVP hash, what it does is it’ll just wait until all the promises within it are returned, and then it’ll return that promise. So notice here, it all loaded at once after all the promises were done loading. And since this hash method wrapping these two promises is also a promise, we can use .then and .catch on it as well. Let’s go ahead and log out the response so we can see what it looks like.

So we can see that the object returned, the promise returned, has an array of worlds and an array of monsters. Of course to make these monsters show up, I did have to change this line to say model.monsters instead of just model like it was before. And then of course we can add in code so we can view the worlds. And then on our page, we can see the worlds displayed, loaded at the exact same time as the monsters, as far as the user is concerned.

We should also note that an RSVP hash doesn’t take just promises. It can also take just regular values. So we’ll set taco to true, and it’ll handle it just fine. See it loads taco as true, and then the worlds and monsters as they were before.

Now what happens if one of these throws an error? Let’s go ahead and reject the taco, and we’ll do it using the Ember.RSVP.reject shortcut, and we’ll create a catch function and see what that gives us.

So we can see several things from this result. The first is that the monsters and the worlds, they don’t load, even though as we can see here, the XHR, the ajax request, happened perfectly fine, but they’re not showing up because our promise, our hash, was rejected. We’ll also see that the rejected reason is given as ‘undefined’. That’s because we didn’t put anything in here. And now, it’ll say ‘Oops’ instead of ‘undefined’.

So this is using hash which has a fail-fast error handling. So if any of these fail, then it’s straight to the catch block for all of them. If we use hashSettled, then it’s a little bit different. So while the monsters and the worlds still don’t display, it gives us the response in the .then

So notice the response was is the log that we have in the .then, not in the .catch. And then this object, it has stuff for the monsters, the taco, and the worlds. One thing you’ll notice is that each of these, so taco, it’s in the state ‘rejected’ and the reason given is ‘Oops’, and worlds will be in the state ‘fulfilled’ and it has a value of ‘all the worlds’.

So so far we’ve talked about hash and hashSettled, and as you can see there are a lot more. We did touch on briefly the reject method, and it has a companion method of resolve, so you can do Ember.RSVP.resolve to just send back a promise. Some other ones of note are the all and allSettled. So all just takes an array rather than object or a hash, like hash does. And then allSettled is the array equivalent of hashSettled. Also map is very similar to JavaScript map in that it does an action on each of the promises or each of the results of the promises that come in.

So that’s it for today. I hope you’ll join us next week as we go into other types of asynchronous abstractions like generators and Async/Await. I’ll see you then.

ESNext

Subscribe to our mailing list