Concepts/JavaScript

Promises vs async/await

async/await is syntactic sugar over Promises. Both handle asynchronous operations, but async/await reads like synchronous code while Promises use .then() chaining.

Side-by-Side Comparison

FeaturePromises (.then/.catch)async/await
Syntax styleChain-based (.then/.catch)Sequential (await keyword)
Error handling.catch() at chain endtry/catch blocks
ReadabilityCan become nested with complex flowsReads like synchronous code
DebuggingStack traces can be harder to followBetter stack traces, easier to step through
Parallel executionNatural with Promise.all()Requires explicit Promise.all()

Code Examples

Promises (.then/.catch)

  • Chain-based API with .then(), .catch(), .finally()
  • Each .then() returns a new Promise
  • Can handle multiple async operations with Promise.all/race/allSettled
  • Error handling via .catch() at end of chain
function fetchUserData(id) {
  return fetch(`/api/users/${id}`)
    .then(res => res.json())
    .then(user => fetch(`/api/posts/${user.name}`))
    .then(res => res.json())
    .catch(err => console.error('Failed:', err))
}

async/await

  • Syntactic sugar over Promises — same underlying mechanism
  • Makes async code read like synchronous code
  • Error handling via try/catch (familiar pattern)
  • async function always returns a Promise
async function fetchUserData(id) {
  try {
    const res = await fetch(`/api/users/${id}`)
    const user = await res.json()
    const postsRes = await fetch(`/api/posts/${user.name}`)
    return await postsRes.json()
  } catch (err) {
    console.error('Failed:', err)
  }
}

When to Use Which

async/await

Default choice for sequential async operations, complex error handling, and any code where readability matters. Use for most async code.

Promises (.then/.catch)

Better for parallel operations (Promise.all), simple transformations, and when building composable async utilities. Also needed in non-async contexts.

Common Mistakes

Interview Questions

Can you use await at the top level?

Yes, in ES modules (not CommonJS). Top-level await was introduced in ES2022. In Node.js, the file must use .mjs extension or have "type": "module" in package.json.

What happens if you forget await before a Promise?

The code continues without waiting for resolution. The variable holds the pending Promise object instead of the resolved value. This is a common source of bugs — the code appears to work but processes data incorrectly.

How would you run 5 API calls in parallel with async/await?

Use Promise.all(): `const results = await Promise.all([fetch(url1), fetch(url2), ...])`. Each fetch runs concurrently and await pauses until all resolve. For partial failure tolerance, use Promise.allSettled() instead.

Deep Dive