async/await: Sequential Shape, Concurrent Power
intermediate15 min readLesson 73 of 143
Async functions, await semantics, try/catch over async code, and loops — sequential await vs parallel Promise.all.
async/await is promise syntax sugar — same machinery, readable shape.
The rules
async functionalways returns a promise; returning a value wraps it, throwing rejects it.awaitpauses only the async function, not the thread: the rest of the program keeps running (event loop lesson).awaitworks on any thenable — and unwraps in a microtask, soawaitorder follows microtask order.
async function loadDashboard(userId) {
try {
const user = await getUser(userId); // sequential: needs user.id
const orders = await getOrders(user.id);
return { user, orders };
} catch (err) {
return { error: "Could not load dashboard" }; // catches both awaits
}
}
try/catch works across await — one of its best features. Remember it only
catches errors inside the try block at await time; a forgotten await leaks
a floating promise whose rejection nothing catches.
The classic trap: await in a loop
// SLOW: one request at a time (unless each needs the previous)
for (const id of ids) results.push(await fetchOne(id));
// FAST: all in flight at once
const results = await Promise.all(ids.map(fetchOne));
Sequential await is correct when step N needs step N-1's output; otherwise it is wasted latency. The combinator lesson formalizes this.