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 .then
s, the ajax
promises, the jquery
promises, can’t take the .catch
s or .finally
s. 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.