JavaScript Async and Await
December 11, 2019
Async functions
The word “async” before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically.
For instance, this function returns a resolved promise with the result of 1, let’s test it:
async function f() {
return 1;
}
f().then(alert); // 1
We could explicitly return a promise, that would be the same:
async function f() {
return Promise.resolve(1);
}
f().then(alert); // 1
So, async ensures that the function returns a promise, and wraps non-promises in it.
Await
The keyword await makes JavaScript wait until that promise settles and returns its result.
Here’s an example with a promise that resolves in 1 second:
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // wait until the promise resolves (*)
alert(result); // "done!"
}
f();
The function execution “pauses” at the line (*) and resumes when the promise settles, with result becoming its result. So the code above shows “done!” in one second.
Let’s emphasize: await literally makes JavaScript wait until the promise settles, and then go on with the result. That doesn’t cost any CPU resources, because the engine can do other jobs meanwhile: execute other scripts, handle events etc.
It’s just a more elegant syntax of getting the promise result than promise.then, easier to read and write.
Can’t use await in regular functions
If we try to use await in non-async function, there would be a syntax error:
function f() {
let promise = Promise.resolve(1);
let result = await promise; // Syntax error
}
We will get this error if we do not put async before a function. As said, await only works inside an async function.
Promises chaining
fetch('/article/promise-chaining/user.json')
.then(response => response.json())
.then(user => fetch(`https://api.github.com/users/${user.name}`))
.then(response => response.json())
.then(githubUser => new Promise(function(resolve, reject) { // (*)
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
setTimeout(() => {
img.remove();
resolve(githubUser); // (**)
}, 3000);
}))
// triggers after 3 seconds
.then(githubUser => alert(`Finished showing ${githubUser.name}`));
Rewrite using async/await
We’ll need to replace .then calls with await. Also we should make the function async for them to work.
async function showAvatar() {
// read our JSON
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();
// read github user
let githubResponse = await fetch(`https://api.github.com/users/${user.name}`);
let githubUser = await githubResponse.json();
// show the avatar
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
// wait 3 seconds
await new Promise((resolve, reject) => setTimeout(resolve, 3000));
img.remove();
return githubUser;
}
showAvatar();
0:0:42 An example of Asynchronous JavaScript 0:7:06 Understanding Asynchronous JavaScript : The Event Loop 0:15:50 The old way : JavaScript with Callbacks 0:25:12 From Callback hell to Promises