Study notes · 11% of the exam

Promises and async/await

Promises represent the eventual result of an operation. Know how settlement, chaining, the combinators and async/await work, and why promises can't cancel or restart the work behind them.

Key points

  1. 1

    A promise settles once: later resolve/reject calls are ignored. The executor runs synchronously, and a throw inside it becomes a rejection.

  2. 2

    Every then/catch/finally returns a new promise. Returned values fulfil it, thrown errors reject it, and returned promises are adopted. Adopting a returned native promise costs two extra microtasks.

  3. 3

    all fails fast, allSettled reports every outcome, race copies the first settlement, and any waits for the first success or rejects with an AggregateError. None of them cancels the losers.

  4. 4

    Async functions always return a promise and run synchronously until the first await. Inside try, use return await so rejections reach catch.

  5. 5

    Start independent work before awaiting it, but combine the promises with Promise.all so every rejection has a handler.

  6. 6

    Cancellation is cooperative: pass an AbortSignal to APIs that accept one, check signal.throwIfAborted() in your own loops, and use AbortSignal.timeout/any for deadlines.

  7. 7

    To retry, call a function again; a promise is a finished result and can't be re-run.

Common traps

  • array.forEach(async ...) does not wait for the callbacks, and loses their rejections.

  • A timeout built with Promise.race leaves the original work running, and in Node.js the timer can keep the process alive.

  • A promise that rejects before anything awaits it is an unhandled rejection. Since Node 15 that crashes the process by default.

Test yourself on Promises and async/await

Ten questions, with the answer and explanation after each one.