async / await, Deeply
What await really pauses, why sequential awaits are often a performance bug, and how errors propagate.
async function f() {
const [a, b] = await Promise.all([p1, p2]);
}await does not block the thread -- it suspends the async function, hands control back to the event loop, and resumes when the awaited promise settles. An async function always returns a promise; return x resolves it, throw rejects it.
The sequential-await trap
Awaiting independent tasks one after another makes them run in series for no reason:
const a = await slow(); // 1s
const b = await slow(); // another 1s -- total 2s, wastedIf they do not depend on each other, start them together and await the group with Promise.all -- total time drops to the slowest one.
Error handling
A rejected await throws at the await point, so ordinary try/catch works. An unhandled rejection propagates out as the returned promise's rejection -- always .catch or await the call somewhere.
Example
When to use it
- Abort a stale fetch request using AbortController when the user navigates away before the response arrives.
- Implement sequential pagination by awaiting each page fetch inside a while loop.
- Avoid unhandled promise rejections by always pairing every async call with error handling.
More examples
Async iteration over pages
Loops through paginated API pages using sequential awaits, stopping when an empty page is returned.
async function fetchAllPages(baseUrl) {
let page = 1;
const all = [];
while (true) {
const res = await fetch(`${baseUrl}?page=${page}`);
const data = await res.json();
if (!data.length) break;
all.push(...data);
page++;
}
return all;
}AbortController for cancellation
Passes a signal to fetch and calls abort() to cancel it, triggering an AbortError in the catch.
const controller = new AbortController();
const { signal } = controller;
fetch("/api/data", { signal })
.then(r => r.json())
.catch(e => console.log(e.name)); // "AbortError"
controller.abort(); // cancel the requestParallel with error isolation
Wraps Promise.allSettled to return null for any rejected promise instead of throwing.
async function safeAll(promises) {
return Promise.allSettled(promises).then(results =>
results.map(r => r.status === "fulfilled" ? r.value : null)
);
}
const data = await safeAll([
fetch("/api/a").then(r => r.json()),
Promise.reject(new Error("B down")),
fetch("/api/c").then(r => r.json())
]);
console.log(data); // [resultA, null, resultC]
Discussion