Skip to main content
๐Ÿ“œ WAYPOINT LESSON

async/await: Sequential Shape, Concurrent Power

โญโญ intermediateโณ 15 min read๐Ÿ“ Lesson 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 function always returns a promise; returning a value wraps it, throwing rejects it.
  • await pauses only the async function, not the thread: the rest of the program keeps running (event loop lesson).
  • await works on any thenable โ€” and unwraps in a microtask, so await order 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.