Simple Explanation of async/await in JavaScript

In my post on JavaScript promises I described a promise as an object that represents a result that isn’t ready yet. async and await are syntax that lets you work with those objects without a pile of .then() calls.

The same code, two ways

With promises:

function showUser(id) {
  return getUser(id)
    .then((user) => render(user))
    .catch((err) => showError(err));
}

With async/await:

async function showUser(id) {
  try {
    const user = await getUser(id);
    render(user);
  } catch (err) {
    showError(err);
  }
}

Both do the same thing. The second reads top to bottom like synchronous code.

Two rules to remember

  1. An async function always returns a promise. Whatever you return gets wrapped, and anything you throw becomes a rejection.
  2. await can only pause inside an async function (or at the top level of an ES module). It pauses that function, not the whole program.

Mistake 1: awaiting in a loop when you don’t need to

// Sequential: each request waits for the previous one
for (const id of ids) {
  users.push(await getUser(id));
}

// Parallel: all requests start immediately
const users = await Promise.all(ids.map((id) => getUser(id)));

If the calls don’t depend on each other, run them together. On ten requests of 200 ms each, that is about 2 seconds versus about 200 ms.

Mistake 2: forEach doesn’t wait

ids.forEach(async (id) => {
  await save(id); // forEach ignores the returned promise
});
console.log("done"); // runs before the saves finish

Use for...of if you need order, or Promise.all with map if you don’t.

When one failure shouldn’t sink everything

Promise.all rejects as soon as any promise rejects. If you want every result regardless, use Promise.allSettled:

const results = await Promise.allSettled(ids.map(getUser));
const ok = results.filter((r) => r.status === "fulfilled").map((r) => r.value);

Takeaway

Think of await as “wait for this promise, then continue”. Use Promise.all when work can overlap, and always wrap awaits in try/catch (or handle the rejection at the call site).