Instructor: Here, we have the Query API function from the previous lesson again. In this lesson, I want to show you how to use async functions and the await operator to interact with promises. I'm going to start by creating a function called main and I'm going to invoke it right away.
I'm going to call Query API and pass out the films endpoint. Now, what we get back from this function call is our films prompts. I'm going to log it to the console, just so we can convince ourselves this is actually a promise. Let's refresh the page, and sure enough we can see that we do get back a promise.
Here is where it gets interesting. I'm going to make this an asynchronous function by adding the async keyword to the function declaration. Within async functions, we can use the await operator to wait for any promise to settle.
The await operator will pass the function execution until this promise has been settled. When this promise is fulfilled, the await expression takes on the value that the promise was resolved with. In our case, that's the JSON that we got back from the API.
We're going to look at what happens with rejected promises in a minute. For now, let's go ahead and rename our variable to be just films, because we no longer get back a promise. We get back the films themselves.
I'm going to read out the page and you can see our six films. Let's show the number of films in the UI. Let's also get rid of this spinner once we're done. Refresh this again.
Now, we see six films. Let's now take a look at what happens when this promise is rejected. I'm going to try to load an endpoint that doesn't exist. As you can see, we get a four of four and an uncalled promise error.
When the await operator is applied through a rejected promise, it throws an error. Now, when there is an error within an asynchronous function, the asynchronous function implicitly returns a rejected promise. This means that we now have a rejected promise here.
We didn't attach any rejection handlers. This is why it's an uncalled promise error. We can fix this by adding a rejection handler here. Let's log the error to the console. Let's show a very helpful error message to the user. Let's also remove the spinner.
While this approach works, it is not a great solution. We now have logic in two places. We also have duplicate code. Luckily, we can use a cleaner error handling strategy with the await operator and that is a plain old try catch statement.
I'm going to wrap this in a try block and I'm going to add our error handling logic in a catch block. I'm also going to add a finally block, so that we can make sure that we always remove this spinner, even if there was an error in the catch block.
Let's run this again. We still see the error messages. Let's now run the happy path, and that looks good as well. Notice that we've written asynchronous code that looks fairly synchronous. You can read the entire main function line by line top to bottom, and you get the control flow you'd probably expect. This is one of the big benefits of using async await.
Let's say we also want to show the number of planets like we did in the previous lesson. We're going to make another request to the API, but this time we're going to load the planets endpoint.
Reload the page and we see 60 planets. However, if we take a look at the network tab, we can see that we're making both API requests sequentially rather than in parallel. This is because we're only kicking off the second request after the first promise has already been fulfilled.
This is the perfect use case for the promise.all method. We want to make both requests at the same time and wait for both responses to come back. We can then await the promise return by promise.all, and we can also immediately destructure the results into the local variables, films and planets.
Perfect. We now make both requests in parallel. I really like the combination of destructuring the await operator and the promise.all method. With very little syntax, we can add a third request here.
Let's refresh this once more. We now see three API requests that are in-flight at the same time. To show you one more example of how the await operator can be used, I'm going to refactor the Query API function into an asynchronous function as well.
First, we're going to make this an async function by adding the async keyword. Second, we're going to get rid of this callback and instead, we're going to await the promise that is returned by fetch.
Finally, I'm going to convert this conditional expression into a proper if statement. If the response is OK, we want to deserialize the body as JSON and return the promise. Otherwise, we want to throw an error. Notice that this is looking simpler than before as well.
I find this logic easier to understand. Let's give this one last refresh, and there you go. Async await working seamlessly with promises.