Async and Await

In this lesson, you will discover how async and await, the latest additions to asynchronous JavaScript, build on top of promises.

Async functions and the await keyword, new additions in ECMAScript 2017, act as syntactic sugar on top of promises. They allow us to write synchronous-looking code while performing asynchronous tasks behind the scenes.

Async

First, we have the async keyword. We put it in front of a function declaration to turn it into an async function.

async function getData(url) {}

Invoking the function now returns a promise. This is one of the traits of async functions; their return values are converted to promises.

Async functions enable us to write promise-based code as if it were synchronous, without blocking the execution thread and instead operating asynchronously.

However, async alone does not make the magic happen. The next step is to use the await keyword inside the function.

Await

The real advantage of async functions becomes apparent when you combine them with the await keyword. Await can only be used inside an async block, where it makes JavaScript wait until a promise returns a result.

let value = await promise

The await keyword makes JavaScript pause at that line until the promise settles and returns its result, and then it resumes code execution.

It’s a more elegant syntax of getting the result from a promise than promise.then().

Fetch

fetch() allows us to make network requests similar to XMLHttpRequest (XHR). The main difference is that the Fetch API uses promises, which enables a simpler and cleaner API, avoiding callbacks.

The simplest use of fetch() takes one argument — the path to the resource — and returns a promise containing the response.

async getData(url) {
  const data = await fetch(url);
  return data;
}

In our code, we wait for fetch() to return with the data before we return it from the function.

Now, we have our function ready. Remember, since it returns a promise, we need to use then() to get hold of the value.

getData(url).then((data) => console.log(data));

Otherwise, we can even write this shorthand:

getData(url).then(console.log);

Now, we have all the basics of expected behavior figured out, but what if something unexpected happens?

Error handling

If await promise is rejected, it throws the error, just as if there were a throw statement at that line. We can catch that error using try/catch; this is the same way we catch an error in regular code.

async getData(url) {
  try {
    const data = await fetch(url);
    return data;
  } catch(error) {
    // Handle error
  }
}

If we don’t have the try/catch, the promise generated by calling the async function becomes rejected. We can append .catch() to handle this:

getData(url).catch(alert);

If we don’t add a .catch(), we get an unhandled promise error. We can catch such errors using a global error handler.

Conclusion

The async keyword is added to functions to tell them to return a promise rather than directly returning the value.

The await keyword can only be used inside an async block, where it makes JavaScript wait until a promise returns a result.

With fetch(), we can make network requests that return promises.

Next, let’s see how we can use what we have discussed to save our high scores asynchronously.


Quiz on async and await

Get hands-on with 1200+ tech skills courses.