Example of async/await in JavaScript
ES2016 introduced async
functions. This feature was proposed by Brian Terlson. async/await
construct is inspired by .NET.
The goal of async
function is to write code as if each instruction would be executed one after another (synchronously) but still having the things done asynchronously.
An async function
returns a promise.
Aside
For the sake of this article we are going to use the following utility functions. The first one just render an article in the DOM. The second one just performs an HTTP request in Ajax using the XMLHttpRequest object.
const renderPost = (body, post) => {
const section = document.createElement('section');
const domString = `
<p>
<strong>Post: </strong>${post.title}
</p>
<p>
<strong>Author: </strong>${post.author.firstName}
</p>
`;
section.innerHTML = domString;
body.appendChild(section);
};
const get = (url, success, error) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = (e) => {
if(xhr.readyState === 4) {
if(xhr.status === 200){
success(xhr.responseText);
}
else{
error(xhr);
}
}
};
xhr.send(null);
};
Asynchronicity
JS is an asynchronous language. It means that instructions are not necessarily done one after another. Certain instructions such as network operations are indeed non-blocking. Code snippet speaks a thousand words.
const students = [
{firstName: 'Steven', age: 18},
{firstName: 'Frederik', age: 20}
];
students.forEach( (student, index) => {
setTimeout( () => {
console.log( `${student.firstName} is ${student.age}`);
}, 10000*index);
});
console.log('Log all students name and age.');
The order in which the instructions are executed is the following.
Log all students name and age.
Steven is 18
Frederik is 20
(10 seconds later)
Asynchronicity allows to start multiple tasks in parallel without waiting for one task to be completed before starting with the next task. For example start downloading a second file while the first file is still downloading.
Callback
A callback is a function passed as a parameter to another function.
One very common usage of callback is the continuation-passing style (CPS), for having things done asynchronously. In such a case, the callback will be called by the higher order function upon event occurrence (e.g. HTTP request has been resolved).
In the previous code snippet setTimeout
takes the following callback as parameter.
() => {
console.log(`${student.firstName} is ${student.age}`);
}
Callback hell
Nested callbacks is the so-called callback hell also known as pyramid of doom. The following code snippet speaks for itself.
get("/post/9", (response1) => {
const post = JSON.parse(response1);
get(`/author/${post.authorId}`, (response2) => {
const author = JSON.parse(response2);
const body = document.body;
const aggregatedPost = {...post, author};
renderPost(body, aggregatedPost);
});
});
Promise
Promise has been introduced for avoiding the so-called callback hell. A promise is actually a concept pretty close to the callback. A promise is actually a container for callback. Let’s have an example using the fetch API which returns a promise.
const promisePost = fetch("/post/9")
.then( (response) => response.json());
const promiseAuthor = promisePost
.then((post) => fetch(`/author/${post.authorId}`))
.then((response) => response.json());
Promise.all([promisePost, promiseAuthor])
.then(([post, author]) => {
const aggregatedPost = {...post, author};
renderPost(document.body, aggregatedPost);
})
.catch((e) => console.error(e));
async/await
async
function allows to write same code as promise allows but in a more readable way (syntactic sugar). Let’s rewrite the example above in using async/await
.
async function fetchAndRenderPost(){
const promisePost = await fetch("/post/9");
const postParsed = await promisePost.json();
const promiseAuthor = await fetch(`/author/${post.authorId}`);
const authorParsed = await promiseAuthor.json();
const aggregatedPost = {...postParsed, authorParsed};
renderPost(document.body, aggregatedPost);
}
fetchAndRenderPost();
Conclusion
This article was just about having a very simple example of async/await
and at the same time briefly recalling the background surrounding the topic.
Feel free to clone the repo created for the sake of this tutorial for playing around with the concepts exposed above.