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 is a senior UI engineer at Microsoft.