async/await in JavaScript
Introduction
async/await is syntax for working with Promises without long .then chains. An async function always returns a Promise; await pauses that function until a Promise settles. This chapter focuses on patterns, pitfalls, and parallel vs sequential flows used in real apps.
Prerequisites
Basic async Function
javascript
// async always returns a Promise
async function doubleAfterDelay(n) {
await new Promise((resolve) => setTimeout(resolve, 50));
return n * 2;
}
const result = await doubleAfterDelay(3);
console.log(result);Top-level await works in ES modules (type: "module" or .mjs).
try/catch with await
javascript
async function loadProfile(id) {
try {
const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
console.error("loadProfile:", err.message);
return null;
}
}
console.log(await loadProfile(1));Rejected Promises from await throw inside try like sync exceptions.
Sequential vs Parallel
javascript
// Sequential — slower total time
async function sequential() {
const a = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const b = await fetch("https://jsonplaceholder.typicode.com/todos/2");
return [await a.json(), await b.json()];
}
// Parallel — start together
async function parallel() {
const [resA, resB] = await Promise.all([
fetch("https://jsonplaceholder.typicode.com/todos/1"),
fetch("https://jsonplaceholder.typicode.com/todos/2"),
]);
return [await resA.json(), await resB.json()];
}
const t0 = Date.now();
await parallel();
console.log("parallel ms", Date.now() - t0);Use Promise.all when tasks are independent.
Promise.allSettled for Partial Success
javascript
async function fetchMany(urls) {
const results = await Promise.allSettled(
urls.map((url) => fetch(url).then((r) => r.json()))
);
return results.map((r) =>
r.status === "fulfilled" ? r.value : { error: r.reason.message }
);
}
console.log(
await fetchMany([
"https://jsonplaceholder.typicode.com/todos/1",
"https://invalid.example/data",
])
);Async in Array Methods
javascript
// Wrong: forEach ignores async — callbacks fire without awaiting
const ids = [1, 2, 3];
// Right: for...of awaits each step
async function loadAllSequential(ids) {
const out = [];
for (const id of ids) {
const res = await fetch(
`https://jsonplaceholder.typicode.com/todos/${id}`
);
out.push(await res.json());
}
return out;
}
// Or parallel
async function loadAllParallel(ids) {
const resList = await Promise.all(
ids.map((id) =>
fetch(`https://jsonplaceholder.typicode.com/todos/${id}`).then((r) =>
r.json()
)
)
);
return resList;
}IIFE for Scripts Without Top-Level await
javascript
// Classic script without module
(async () => {
const data = await fetch("https://jsonplaceholder.typicode.com/todos/1").then(
(r) => r.json()
);
console.log(data);
})();Mini Example: Retry with await
javascript
async function withRetry(fn, max = 3) {
for (let attempt = 1; attempt <= max; attempt++) {
try {
return await fn();
} catch (err) {
if (attempt === max) throw err;
await new Promise((r) => setTimeout(r, 200 * attempt));
}
}
}
await withRetry(async () => {
const res = await fetch("https://example.com");
if (!res.ok) throw new Error("bad status");
return res.status;
});FAQ
await blocks the whole program?
Only the current async function—other events and callbacks still run on the main thread.
Return value of async?
Wrapping in Promise.resolve—return 5 becomes Promise fulfilled with 5.
Mix await and .then?
Valid but pick one style per function for readability.