This lesson shows how regular control flow statements such as try
/catch
blocks can be used to properly handle errors in asynchronous functions. Oftentimes, the resulting code is easier to read than complex promise chains with .catch()
methods.
[00:00] Here, we have the fetch GitHub user function again, which goes to the GitHub API, and loads a specific user.
[00:06] What happens if we try to load a user that doesn't actually exist? Let's run the program. We get undefined and undefined. Let's see what the response object looks like.
[00:20] We're going to log the entire object to the console and run the program again. As we can see, we get back an object with two properties -- message and documentation URL -- if the user doesn't exist.
[00:32] Our fetch GitHub user function always returns a promise, which is resolved with this value. This is not what we want. Instead, we want to reject this promise with the error message.
[00:43] First, let's store the return value of the JSON function in a variable. We'll say if the response was not successful -- if the status code was not 200 -- we want to throw an error. We want to pass it the message property that we got from the body.
[01:01] We can now add a catch method to our promise chain, and log the error to the console, like this. If we now run the program again, we get the expected error message. This approach works because an asynchronous function will automatically return a rejected promise whenever an error is thrown.
[01:24] This is why we can simply write a catch method, and then deal with the rejected promise. Another advantage of the async and await keywords is that we can use regular try...catch statements.
[01:34] This is not possible with plain promises because the callback function is always invoked asynchronously. To illustrate how async and await can be combined with try...catch blocks, I'm first going to convert this promise chain into an asynchronous function. Within this function, we're going to have a regular try...catch statement.
[01:53] We are going to attempt to load the user. We'll say const user=await fetch GitHub user. If that succeeds, we're going to log to the console the user's name and location. The await operator will wait until the promise is settled, and if it's rejected, it'll throw an error.
[02:17] If something goes wrong, we'll simply end up in the catch block, and then we'll log the error to the console.
[02:23] Finally, we'll call the function with a user that doesn't exist. We can confirm that we still get the same result. Let's also make sure that the success case still works, and indeed, it does.
Funnily it looks like someone has created a github account with the idonotexist username...
const fetch = require('node-fetch')
- does this mean it's only possible server-side?