TypeOfNaN

How Does Async-Await Work in JavaScript

Nick Scialli
November 30, 2020

Async/await is sometimes referred to as “syntactic sugar” on top of Promises. But what does that really mean? The answer is actually pretty simple: async/await is really just promises under the hood but with a different (some would say simpler) syntax.

Let’s use a pretty common example of promises: fetching data.

Fetching Data with Promises

We will start out by using the browser’s built-in fetch function. When you pass a URL to fetch, it returns a promise. Once that promise resolves with the response, we can use the .json() method on that response to return yet another promise. That promise will resolve with the json body of the request response.

Here’s all of this in action fetching some user data from the GitHub public API.

fetch('https://api.github.com/users/nas5w')
  .then((res) => res.json())
  .then((data) => {
    console.log(data);
  })
  .catch((err) => {
    console.error(err);
  });

/*

{
  "login": "nas5w",
  "id": 7538045,
  "node_id": "MDQ6VXNlcjc1MzgwNDU=",
  "avatar_url": "https://avatars2.githubusercontent.com/u/7538045?v=4",
  "gravatar_id": "",
  "url": "https://api.github.com/users/nas5w",
  "html_url": "https://github.com/nas5w",
  "followers_url": "https://api.github.com/users/nas5w/followers",
  "following_url": "https://api.github.com/users/nas5w/following{/other_user}",
  "gists_url": "https://api.github.com/users/nas5w/gists{/gist_id}",
  "starred_url": "https://api.github.com/users/nas5w/starred{/owner}{/repo}",
  "subscriptions_url": "https://api.github.com/users/nas5w/subscriptions",
  "organizations_url": "https://api.github.com/users/nas5w/orgs",
  "repos_url": "https://api.github.com/users/nas5w/repos",
  "events_url": "https://api.github.com/users/nas5w/events{/privacy}",
  "received_events_url": "https://api.github.com/users/nas5w/received_events",
  "type": "User",
  "site_admin": false,
  "name": "Nick Scialli",
  "company": null,
  "blog": "http://www.twitter.com/nas5w",
  "location": "Washington, DC",
  "email": null,
  "hireable": null,
  "bio": "Husband, dog dad, software engineer, and data science enthusiast.\r\n",
  "twitter_username": null,
  "public_repos": 44,
  "public_gists": 1,
  "followers": 249,
  "following": 5,
  "created_at": "2014-05-09T21:05:01Z",
  "updated_at": "2020-11-28T15:41:35Z"
}

*/

Great, so if you’re familiar with promises this is probably straightforward at this point.

Adding Async Await

Since async/await still uses promises under the hood, we can use the same example! The way I like to think of async/await is that we’re telling our interpreter that a function is asynchronous (async) and, inside that function, we’ll be waiting (await) for a promise (or multiple promises) to resolve before moving forward.

Let’s see what I mean.

// This is an asynchronous function
async function getGithubData() {
  // Let's wait for the promise returned from fetch to resolve
  const res = await fetch('https://api.github.com/users/nas5w');
  // Let's wait for the promise returned from res.json() to resolve
  const data = await res.json();
  // Now we have our data, let's log it
  console.log(data);
}

You may notice that, if you try to run this, nothing happens! That’s because we tucked this code in an async function but we never called that function. We can go ahead and call it and we should get the same console output as before.

getGithubData();

Great! Now one final step: we need to handle any errors! With promises, we were able to use the promise .catch method. With async/await, we’ll wrap everything in a try/catch block.

async function getGithubData() {
  try {
    const res = await fetch('https://api.github.com/users/nas5w');
    const data = await res.json();
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

getGithubData();

And now you have converted a promise into async/await syntax!

Nick Scialli

Nick Scialli is a senior UI engineer at Microsoft.

© 2024 Nick Scialli