# async / await

## 1. What `async`/`await` Actually Is

`async`/`await` is **syntax sugar over Promises** — it doesn't replace them, it makes code that uses them read like synchronous code, while still being fully asynchronous underneath.

```js
// Promise chain
function loadUser(id) {
  return fetch(`/users/${id}`).then(res => res.json());
}

// Equivalent async/await
async function loadUser(id) {
  const res = await fetch(`/users/${id}`);
  return res.json();
}
```

## 2. `async` Functions Always Return a Promise

```js
async function example() {
  return 42;
}
example(); // Promise { 42 } — NOT the number 42 directly
example().then(value => console.log(value)); // 42
```

If the function body throws, the returned Promise **rejects** instead:

```js
async function fails() {
  throw new Error("boom");
}
fails().catch(e => console.log(e.message)); // "boom"
```

## 3. `await` Pauses the Function, Not the Program

```js
async function example() {
  console.log("1: before await");
  const result = await delay(100, "done"); // pauses HERE, but only this function
  console.log("3: after await:", result);
}
example();
console.log("2: runs immediately — the rest of the program is NOT blocked");
// order: 1, 2, 3
```

`await` can only be used inside an `async function` (or at the top level of an ES module). Everything after `await` is scheduled as a microtask, exactly like a `.then()` callback (see the Microtasks vs Macrotasks topic).

![The function runs up to await, suspends while the rest of the program continues, then resumes as a microtask once the promise settles](diagrams/01-await-pause-resume.svg)

## 4. `await` Unwraps a Promise's Value (or Throws Its Rejection)

```js
async function example() {
  const value = await Promise.resolve(42);   // value = 42, unwrapped automatically
  try {
    await Promise.reject(new Error("failed"));
  } catch (e) {
    console.log(e.message); // "failed" — a rejected awaited Promise throws, catchable with try/catch
  }
}
```

`await` on a rejected Promise behaves exactly like a `throw` — this is what makes `try/catch` work naturally with async code (full detail in the Async Error Handling topic).

## 5. Sequential vs Concurrent `await` (Preview)

```js
// SEQUENTIAL — each await waits for the previous one to finish first
async function sequential() {
  const a = await delay(100, "a"); // waits 100ms
  const b = await delay(100, "b"); // THEN waits another 100ms — total ~200ms
  return [a, b];
}

// CONCURRENT — both start immediately, only wait once
async function concurrent() {
  const [a, b] = await Promise.all([delay(100, "a"), delay(100, "b")]); // total ~100ms
  return [a, b];
}
```

Full depth on this distinction (and when to use each) is covered in the Parallel vs Sequential Async Operations topic — but it's the single most impactful performance decision when writing `async`/`await` code.

## 6. Top-Level `await`

In ES modules, `await` can be used directly at the top level, outside any `async function`:

```js
// inside an ES module (.mjs, or "type": "module")
const data = await fetch("/config.json").then(r => r.json());
console.log(data);
```

## Under the Hood: From Generator-Based Sugar to a Native Suspend Mechanism

### How async/await was originally understood — and transpiled

Before engines implemented `async`/`await` natively, and still today when compiling for older targets (Babel's "regenerator" transform), an async function was modeled as a **generator function plus an automatic driver**: the compiler rewrote every `await expr` into a `yield expr`, then wrapped the whole thing in a helper that repeatedly calls `.next()` on the resulting generator, feeding each yielded Promise's resolved value back in via `.next(value)` — automating exactly the manual "drive a generator with Promises" pattern by hand, using the exact generator suspend/resume mechanics from the Iterators and Generators topic.

```js
// Roughly what async function example() { const x = await foo(); return x + 1; }
// used to desugar to, conceptually:
function example() {
  return driveWithPromises(function* () {
    const x = yield foo();
    return x + 1;
  });
}
```

### Why modern engines no longer implement it this way, literally

This generator-based model works but carries real overhead: extra generator-object allocation, extra microtask ticks per `await` just to drive the machinery. V8's engineering team specifically re-implemented async functions around 2018-2019 to use a more direct native suspend/resume mechanism — conceptually similar to a generator's heap-allocated suspended frame (Iterators and Generators topic), but purpose-built for `async`/`await` rather than routed through the full generator protocol. Part of that work measurably reduced the number of microtask "ticks" needed to resume after each `await` (from multiple ticks down to one) — a genuine, documented performance improvement, not just an implementation detail.

### The practical takeaway

The "async is sugar over generators + Promises" mental model remains the right way to *reason about* what `await` does (suspend here, resume when the awaited Promise settles, propagate rejection as a throw) — but it's worth knowing that on modern engines it is no longer literally true as an implementation fact. This is a good example of the general pattern throughout this course: the *observable* behavior (what section 1-6 describe) is what the spec guarantees and what you should design around; the *literal mechanism* underneath is free to evolve, and has.

## 7. Common Pitfalls

1. **Forgetting an `async` function always returns a Promise** — trying to use its return value directly (without `await` or `.then()`) gives you a Promise object, not the resolved value.
2. **Using `await` inside a non-`async` function** — a `SyntaxError` at parse time; the enclosing function must be declared `async`.
3. **Sequential `await`s that could run concurrently** — awaiting one independent operation, then another, needlessly serializes work that `Promise.all` could run in parallel.
4. **Forgetting to `try/catch` an `await`** — an unhandled rejection from an `await`ed Promise crashes the async function (and, if nothing catches it further up, triggers an `unhandledRejection`).
5. **Mixing `.then()` and `await` inconsistently** in the same function — not wrong, but usually a readability smell; pick one style per function.

## 8. Quick Reference

```
async function f() { ... }        → always returns a Promise
await promise                       → unwraps value, or throws on rejection
await only inside async functions    → (or top-level in ES modules)
try { await x } catch (e) {}         → standard error handling pattern
```
