
Writing Clean Asynchronous Code with Async and Await
Deeply nested callbacks and long .then() chains can make asynchronous control flow and error handling difficult to reason about. Built on top of native JavaScript Promises, async and await allow you to write asynchronous fetch requests that read like synchronous top-to-bottom code—and handle both network and JSON parsing errors in a single try / catch block.
Example
// Promise chain
function loadUser(id) {
return fetch("/api/users/" + id)
.then(function (res) { return res.json(); })
.catch(function (err) { console.error(err); });
}
// Clean async/await equivalent
async function loadUserClean(id) {
try {
const res = await fetch("/api/users/" + id);
return await res.json();
} catch (err) {
console.error(err);
}
}
Input : Asynchronous REST API endpoints
Output : Sequential and parallel async / await functions with explicit HTTP status verification.
Implementation
async function fetchArticleWithComments(articleSlug) {
try {
// Run independent requests in parallel using Promise.all
const responses = await Promise.all([
fetch("/api/articles/" + encodeURIComponent(articleSlug)),
fetch("/api/articles/" + encodeURIComponent(articleSlug) + "/comments")
]);
const articleRes = responses[0];
const commentsRes = responses[1];
if (!articleRes.ok) {
throw new Error("Failed to load article: HTTP " + articleRes.status);
}
const article = await articleRes.json();
const comments = commentsRes.ok ? await commentsRes.json() : [];
return {
article: article,
comments: comments
};
} catch (error) {
console.error("Error loading article view:", error.message);
return null;
}
}
Main Point: Avoid awaiting independent network requests one after another in a serial sequence; wrap independent Promises in await Promise.all([...]) so they fetch concurrently.
Credits
Photo by Markus Spiske