Series: ESNext

Creating New Promises

Published on Nov 20, 2015

Sometimes you want to start a new promise chain or have greater control over the timing of events. By manually creating a promise, you can do that.

In this video we cover creating a new promise and resolving or rejecting the promise. We use two examples- a custom AJAX login and an Ember Data findAll request.


Links

Code

The method that starts the promise chain. Notice the resolve and reject handlers. Notice we can't use the catch block because the ajax call returns a different type of promise than RSVP. We also can't use the finally block. This is one of the reasons we must wrap it in a new promise.

  login(userName, password){
    return new Ember.RSVP.Promise((resolve, reject)=>{
      Ember.$.ajax({
        method: "POST",
        url: '/sessions',
        data: {
          email: userName,
          password: password
        }
      }).then((data)=>{
        var token = data['authentication_token']
        var user_id = data['user_id']
        Cookies.set('userId', user_id)
        Cookies.set('authenticationToken', token)
        this.initializeFromCookie()
        resolve(user_id)
      }, ()=>{
        reject('Username and password did not match')
      })
    })
  },

We also can use promises in the model hook of the route.

export default Ember.Route.extend(Authenticated, {
  model(){
    return new Ember.RSVP.Promise((resolve, reject)=>{
      this.store.findAll('monster').then((response)=>{
        console.log('the response is', response)
        resolve(response)
      }).catch((reason)=>{
        console.log('finding monsters failed', reason)
        reject(reason)
      })
    })
  }
});

Transcript

In our last episode we talked about promises, and we did some really nice, readable things with promises, but we left kind of a mystery how we got this whole promise chain started because get(“session”) isn’t a promise and then login returns a promise. How does it do that?

Well, so you return a new promise, you create a new promise by doing this, Ember.RSVP.Promise, and then as arguments you pass in resolve and reject which are two functions that are passed to every promise. If things are successful then you call resolve and you pass it whatever arguments you want passed back.

So here we’re resolving with the user_id and then if the logId method here, it gets it as an argument. Then if something went wrong, we call the reject method and we send back whatever we want, usually a stream representing the reason. And then, here we use the displayErrors method, and of course we’re grabbing the reason here.

So to get out of a promise, to return from a promise we call either resolve or reject, and we send back the arguments that we want the thing that’s going to handle this promise to have.

So now that we know the basics of creating a promise, let’s go over this one in detail, and we’ll explain why we want to use this here. So here within our promise, the first thing we do is we create an ajax call. This is in itself a promise, but why can’t we just return that? One reason is that jquery promises are slightly different than RSVP promises. One major difference is that although they can both take .thens, the ajax promises, the jquery promises, can’t take the .catchs or .finallys. Beyond that I’m sure there are other reasons and if you’d like to add more in the comments, please do.

Anyway, so our ajax call is a promise, and so it’s thenable, so we call then on it, and we’re getting back the data, so we process the data like we showed in a previous episode, and then we’re taking one piece of that data and we’re calling resolve to return it. So in the happy path, we create this promise and then we create another promise inside there from the ajax call. We go through after that promise returns, we then it, and we take all these steps, and then we resolve. That resolution returns the user_id which is what triggers this then which takes the user_id as an argument. So that’s the happy path.

The sad path is the second function given to .then since the ajax promises don’t have a .catch, we have to use the second function. And .catch in RSVP is just shorthand for a null first function and the function you give it is the second function. Anyways, so all we do here is call reject with the reason which is then caught by this .catch

And that’s how you create a promise and start a promise chain. Let’s go ahead and do another example. So here remember I said this.store.findAll. That returns a promise. And so that is if we wanted to do something with this data afterwards and maybe return something else in the model, then we’re going to have to create a new promise. So we’ll start by creating a new RSVP.Promise and we’ll have a resolve and reject handlers, and we’ll stick our findAll method in there. And that findAll method is thenable, so we’ll do a then, we’ll get the response from it, and then we’ll go ahead and logout the response for now. That’s all we’ll do for now. And then we’ll go ahead and resolve the response, and then we’ll go ahead and add a catch method if something goes wrong. We’ll get the reason, we’ll logout the reason as well as an explanation if finding monsters failed, and then we’ll reject with that reason.

Then when we load the page, we’ll see that it’s logged out correctly as well as loaded correctly. And there’s more stuff you can do in here. For the most common stuff there are helpers that are more Embery, so don’t go doing this all the time, but it’s a good example of how RSVP promises can be created and used.

So that’s it for today. In the future I’ll be talking about how you can handle multiple asynchronous calls in one promise, in either arrays or hashes. I’ll see you then.

ESNext

Subscribe to our mailing list