How do Promises work in JavaScript?

A Promise represents a value that is not yet available. It has three states: pending, fulfilled, or rejected. Chain .then() and .catch() to handle the result.

JavaScriptAsync

Overview

A Promise is an object that represents the eventual completion (or failure) of an async operation. It starts as `pending`, then either becomes `fulfilled` (success) or `rejected` (failure). You handle the outcome with `.then()`, `.catch()`, and `.finally()` - or with `async/await` which is syntactic sugar over Promises.

Key Points

  • •Three states: `pending` → either `fulfilled` (value) or `rejected` (reason).
  • •`.then(onFulfilled, onRejected)` - handle success and/or error.
  • •`.catch(onRejected)` - shorthand for `.then(undefined, onRejected)`.
  • •`.finally(fn)` - runs regardless of outcome; useful for cleanup.
  • •Promises are chainable: each `.then()` returns a new Promise.
  • •`Promise.all([...])` waits for all; `Promise.race([...])` resolves/rejects with the first to settle.

Examples

Creating and consuming a Promise

javascript
const fetchUser = (id) =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      if (id > 0) resolve({ id, name: 'Alice' });
      else        reject(new Error('Invalid ID'));
    }, 500);
  });

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

Promise chaining

javascript
fetch('/api/user/1')
  .then(res  => {
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();   // returns another Promise
  })
  .then(user => user.name)
  .then(name => console.log('User:', name))
  .catch(err => console.error('Failed:', err.message));

Promise.all - run in parallel

javascript
const [user, posts, comments] = await Promise.all([
  fetch('/api/user/1').then(r => r.json()),
  fetch('/api/posts').then(r => r.json()),
  fetch('/api/comments').then(r => r.json()),
]);
// All three requests run simultaneously

If any promise rejects, Promise.all rejects immediately.

Promise.allSettled - handle partial failures

javascript
const results = await Promise.allSettled([
  fetch('/api/fast'),
  fetch('/api/might-fail'),
]);

results.forEach(result => {
  if (result.status === 'fulfilled') console.log(result.value);
  else                               console.error(result.reason);
});

allSettled never rejects - you get all outcomes (success or failure) for each promise.

Pro Tip

Prefer `async/await` syntax over `.then()` chains for readability - but know that they are the same underneath. `async/await` shines for sequential async steps; `Promise.all` is still the best tool for parallel async operations.