Promises & async/await Deep Dive

A Promise is an object representing a value that will be available later, and async/await is the syntax that lets you work with those future values as if the code ran top to bottom.

Learn Promises & async/await Deep Dive in our free Node.js course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…

Part of the free Node.js course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

By the end of this lesson you'll create promises, chain them with then/catch/finally, write clean async/await with try/catch, combine many promises with all, allSettled, race, and any, choose sequential versus parallel, and modernize callback APIs with util.promisify.

What You'll Learn in This Lesson

1️⃣ Creating & Consuming Promises

You create a promise with new Promise((resolve, reject) => {' '}) . Call resolve(value) on success or reject(error) on failure. Consumers attach .then for the result, .catch for errors, and .finally for cleanup that always runs.

The same logic reads far more naturally with async/await . Inside an async function, await pauses until the promise settles, and a rejection throws — so ordinary try/catch handles errors.

2️⃣ Combining Many Promises

Real apps juggle several async operations at once, and four static helpers cover the common cases. Promise.all waits for all and fails fast if any rejects. Promise.allSettled waits for all and never rejects, reporting each outcome. Promise.race settles with the first to finish either way. Promise.any resolves with the first success .

3️⃣ Sequential vs Parallel (and promisify)

One of the most common performance bugs is awaiting independent operations one at a time. If three calls each take 100ms and don't depend on each other, doing them sequentially costs ~300ms; starting them together with Promise.all costs only ~100ms. Await sequentially only when a later step truly needs an earlier result.

Finally, plenty of older APIs still use error-first callbacks. util.promisify wraps one into a promise-returning function so you can await it.

Your turn. The program below works once you fill in the two blanks marked ___ . Follow the 👉 hints, then run it and compare with the expected output.

No blanks this time — just a brief and an outline. Write it yourself, run it, and check your output against the example in the comments. This ties together Promise.allSettled and reading each result's status.

📋 Quick Reference — Combinators

Practice quiz

What does a Promise represent?

  • A value that will exist later, or an error
  • A synchronous return value
  • A network socket
  • A file handle

Answer: A value that will exist later, or an error. A Promise is a placeholder for a future value that eventually resolves or rejects.

Which handler runs whether a promise resolves or rejects?

  • .then
  • .catch
  • .finally
  • .all

Answer: .finally. .finally always runs after settling, making it ideal for cleanup.

How do you handle a rejected promise when using async/await?

  • With .map()
  • With a for loop
  • With try/catch around the await
  • With process.exit

Answer: With try/catch around the await. An awaited rejection throws at the await point, so a surrounding try/catch handles it.

What does Promise.all do if one of its promises rejects?

  • Ignores the rejection
  • Returns the resolved ones only
  • Waits for all then reports each
  • Rejects immediately with that error

Answer: Rejects immediately with that error. Promise.all is all-or-nothing: a single rejection rejects the whole thing and discards other results.

Which combinator waits for every promise and never rejects?

  • Promise.allSettled
  • Promise.all
  • Promise.race
  • Promise.any

Answer: Promise.allSettled. allSettled reports each outcome as fulfilled or rejected and never rejects itself.

What does Promise.race settle with?

  • The slowest promise
  • The first promise to settle, success or failure
  • Only the first success
  • An array of all results

Answer: The first promise to settle, success or failure. race settles as soon as the first promise settles, whether it resolves or rejects.

What does Promise.any resolve with?

  • The first promise to settle
  • The last to resolve
  • The first to resolve, ignoring rejections
  • Every resolved value

Answer: The first to resolve, ignoring rejections. any resolves with the first fulfillment and only rejects if all of them reject.

Three independent 100ms tasks awaited one at a time take roughly how long?

  • 100ms
  • 300ms
  • 0ms
  • 50ms

Answer: 300ms. Sequential awaits add up: 100 + 100 + 100 is about 300ms; Promise.all would be ~100ms.

What does util.promisify do?

  • Speeds up promises
  • Cancels a promise
  • Turns an error-first callback function into a promise-returning one
  • Logs promise rejections

Answer: Turns an error-first callback function into a promise-returning one. promisify wraps a Node-style (err, value) callback API so you can await it.

Why does logging a promise show 'Promise { <pending> }'?

  • The promise failed
  • You forgot to await it (or use .then)
  • The value is null
  • Node is out of memory

Answer: You forgot to await it (or use .then). Without await or .then you log the promise object itself, not its resolved value.