Series: ESNext

Promises Basics

Published on Nov 18, 2015

Promises are a tool for handling asynchronous communication, and they are commonly used in Ember applications. They’re even built in to Ember Data, route handling, and other parts of the Ember source.

This episode introduces the then, catch, and finally blocks, how to chain them together, and how to use them with either named or anonymous functions.


Links

Code

The login action calls a series of methods. The first is login, which starts the promise chain. Each then continues the promise chain. catch catches any errors. finally is called at the end no matter what. Each function here is named, though anonymous functions are allowed. .bind(this) is required for two of them since the function uses this and therefore needs correct scope.

actions: {
    login(){
      let {userName, password} = this.getProperties('userName', 'password');
      this.get("session")
            .login(userName, password)
            .then(this.logId)
            .then(this.successfulLoginTransition.bind(this))
            .catch(this.displayErrors.bind(this))
            .finally(this.sillyLog)
    }
  },

These are the named functions. They are not particularly instructive, but are here for your reference.

  logId(user){
    console.log('user_id', user)
    return "user's ID is " + user
  },

  successfulLoginTransition(user){
    console.log(user)
    this.get('flashMessages').success('You have signed in successfully')
    this.transitionToPreviousRoute()
  },

  displayErrors(reason){
    this.set("showErrors", true)
    this.get('flashMessages').danger(reason)
  },

  sillyLog(){
    console.log('We are done with the promises!')
  },

Transcript

Today’s episode we’re going to be talking about promises. So we’ve used promises in previous episodes, most recently we’ve created the login method which was a promise, and then we used the then and catch methods in order to work with the promise. We’re going to find out more about what those are this week.

Promises are a way of doing asynchronous communication. If you want to talk to a server, local storage, something that might take a little while to get back to you, then promises are a much better option than just callbacks, which is what we were doing before promises. In addition to being included by default within Ember, they’re also worked pretty deeply into the Ember ecosystem. For example, Ember data returns a promise when you do a find or a fetch, and the model hook in a route is set up so it’ll take a promise and then work with it so you don’t have to know that a promise ever happened. It looks like it’s all synchronous, and that’s part of the magic of promises.

So when you’re using a promise, there are three methods that you need to know about. They are then, catch, and finally. So then is what you call when something goes right, catch is what you call when something goes wrong, and finally is what you call no matter what, at the end. So let’s see how that applies to our login method.

So our login method, we created it as a promise and we’ll go more into that, how that happens, in this week’s pro-episode. But we created a promise and it can either resolve or reject. So if it resolves, if things went correctly, then we do whatever is in the then block. So we do a promise .then, and we put in, in this case, an anonymous function here and we do whatever is in there.

And then if something goes poorly, then we call .catch, and you can return a reason, it’s usually a good idea. You can also return something from the then. So you could perhaps do like the user. We just didn’t in this case.

And then you can call finally. Let’s go ahead and create a finally block here. So we put it after all this, and notice we’re chaining them, and then with the finally we can... we’ll just put in a console.log.

Then we’ll go ahead and first we’ll trigger the catch block by putting in an incorrect user name and password, and it does the stuff in the catch block and it also logs 'We are done with the promises'. And then we’ll go ahead and fill out the correct information, and we’ll login, and notice it does the stuff in the success block, and then it still does the finally. And it does this even though we’re transitioning, we’re redirecting during the then block, but it still does the finally, even though we’re going to a different route. We can have our then blocks and our catch blocks and our finally blocks. We can also stack then blocks.

So we can do a series of steps. Let me show you a simple example. So we’re going to add a then block before what we have currently as our first then block. Now in this then block, we’re going to logout the user_id, what we have as the user, and then we’ll just return it, and then we’ll go ahead and put a console.log in the next then block to make sure it’s been passed on. And as you can see, we’ve added a little bit of extra text here so that we can tell that it’s being passed on from this return block, and not directly from the original one.

So let’s access this again. Here we go. We’ve got our first console log, our second log that’s taking in the return value from the first then, and then of course our finally. So to go over this order it does the first then and then whenever this has been returned, it does the second then, and then there have been no thrown errors so it skips the catch block and it goes to the finally block. If at any point there’s an error, or the promise is rejected instead of resolved, it’ll go to the catch block.

So far we’ve only been using anonymous functions, functions that we define for the express purpose of this promise. But we can also have named functions. So we’ll go ahead and take all this and we’ll rename it to logId. And so with just a couple of quick changes, we can have it as a named function and call it like this. Then in our app we’ll see that it works the same way. We could actually do all of these as named methods. So I’m going to do that with a snap of my fingers. So look how cool this is. We can tell what’s happening. So first we login, and then we log the ID, and then we do a successfulLoginTransition. If there’s any errors, we catch and displayErrors, and then finally we do a sillyLog. So this is a beautiful way to structure your code that makes it extremely easy to read, and we can do this, thanks to promises.

Hey, one correction from future Jeffrey. So in these two we’re calling this, but we’re not specifying which this it is here, so we’re going to have to call .bind(this) so we get the context right. Previously that was fine because we were using the fat arrows, but now we aren’t and so we have to do this. In the rest of the video this will not be done like this because I’m making this correction from the future. Alright, now back to the regular show.

In addition to promise’s role in Ember data and the router, they’re also used in the test helpers, specifically the asynchronous test helpers. So all of these are a promise where they return a promise, and so you can visit something, fillIn something, click something, all that, and it will automatically wait until that action is complete. That’s really powerful, and if you’ve ever tried to test Ember into something like Capybara or Cucumber, you know that being able to use promises to help you know when it’s okay to move on rather than just waiting and hope you’ve waited long enough, which is error-prone and slows down your tests. Using promises is much better.

So in this episode we learned about promises, how to chain them, how to use the then, catch, and finally blocks, and how to do named promises, how to put a named method in there. In the next episode, we’ll be showing how to create a promise from scratch, how to start the promise chain like we did in our login method. Then next week we’ll be talking about how to handle multiple concurrent promises using the arrays and hashes. I’ll see you then.

ESNext

Subscribe to our mailing list