All topics
Asyncintermediate

Async/Await Syntax

Syntactic sugar over Promises that lets asynchronous code read like synchronous code, using async functions and the await keyword.

async/await is syntax over promises. The behaviour is identical; the code reads like the synchronous version.

async/await is like reading a recipe with 'wait for the water to boil' written as one instruction, instead of manually describing checking the pot every few seconds.

Key Concepts

1
    // promises
    function load(id) {
      return fetchUser(id)
        .then(u => fetchOrders(u.id))
        .then(o => render(o))
        .catch(handle);
    }
2
    // async/await
    async function load(id) {
      try {
        const u = await fetchUser(id);
        const o = await fetchOrders(u.id);
        render(o);
      } catch (e) {
        handle(e);
      }
    }
3
An async function always returns a promise, whatever you return inside it:
async
4
    async function f() { return 1; }
    f();              // Promise { 1 }
    await f();        // 1
5
await pauses the function, not the thread. Everything else continues — other events, other timers. It suspends this function until the promise settles.
await
6
The mistake that costs the most: awaiting in a loop.
    // sequential -- 3 seconds for 3 one-second requests
    for (const id of ids) {
      results.push(await fetch(id));
    }
7
    // concurrent -- about 1 second
    const results = await Promise.all(ids.map(id => fetch(id)));
8
The first is correct when each request depends on the previous one. When they are independent it is three times slower for no reason, and it is the most common async performance problem in real code.
9
try/catch works, which callbacks never allowed. An await that rejects throws at that line, so ordinary error handling applies — including finally.
try/catchawaitfinally
10
Top-level await works in ES modules, and not in scripts:
await
11
    // module.mjs
    const data = await fetch(url);      // fine
12
Outside a module it needs the IIFE wrapper.
13
Mixing the two styles is fine and sometimes better.
    const [user, settings] = await Promise.all([
      fetchUser(id),
      fetchSettings(id)
    ]);
14
await for sequencing, Promise.all for concurrency. Using only await is what produces the accidental sequential code above.
awaitPromise.all
15
What the interviewer is probing.1. "What does an async function always return?" Probing: the wrapper. Stalls: "Whatever you return." Moves up: a promise wrapping that value, so a caller still awaits or chains it.
16
2. "How do you handle errors with await?" Probing: the mechanism. Stalls: "Use .catch." Moves up: try/catch, because await turns a rejection into a thrown exception.
17
3. "What is wrong with awaiting in a loop?" Probing: the serialisation. Stalls: "Nothing." Moves up: each iteration waits for the previous one; if they are independent, start them all and await Promise.all.
18
4. "Can you use await at the top level?" Probing: module context. Stalls: "No." Moves up: yes in ES modules, not in CommonJS or a classic script — which is why an async IIFE is still seen.