stackademic

The leading education platform for anyone with an interest in software development.

Promises

Handle asynchronous results with then, catch, and Promise combinators

Overview

A Promise represents a value that may be available now, later, or never. Promises have three states: pending, fulfilled, or rejected. They replace deeply nested callbacks with chainable .then() handlers.

Syntax / Usage

const fetchUser = (id) =>
  new Promise((resolve, reject) => {
    if (!id) reject(new Error('Missing id'))
    else resolve({ id, name: 'Ada' })
  })

fetchUser(1)
  .then((user) => console.log(user.name))
  .catch((err) => console.error(err))
  .finally(() => console.log('done'))

// Creating resolved/rejected promises
Promise.resolve(42)
Promise.reject(new Error('fail'))

// Combinators
Promise.all([p1, p2])       // all succeed or first reject
Promise.allSettled([p1, p2]) // wait for all, never rejects
Promise.race([p1, p2])      // first settled wins

Examples

Fetch JSON from an API:

function getJson(url) {
  return fetch(url).then((res) => {
    if (!res.ok) throw new Error(`HTTP ${res.status}`)
    return res.json()
  })
}

getJson('/api/users/1')
  .then((user) => renderProfile(user))
  .catch(showError)

Retry with exponential backoff:

function delay(ms) {
  return new Promise((r) => setTimeout(r, ms))
}

async function fetchWithRetry(url, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fetch(url)
    } catch (err) {
      if (i === attempts - 1) throw err
      await delay(2 ** i * 100)
    }
  }
}

Common Mistakes

  • Forgetting to return a promise inside .then, breaking the chain
  • Unhandled rejections—always attach .catch() or use async/await with try/catch
  • Assuming Promise.all runs sequentially—it runs in parallel
  • Creating promises without settling them (missing resolve/reject)

See Also

async-await fetch-api functions closures