Promises in JavaScript

Introduction

A Promise represents a value that may arrive later—success or failure. Promises replace deep callback nesting with chainable .then / .catch and work cleanly with async / await. They are the standard for fetch, database drivers, and file APIs in modern JavaScript.

Prerequisites

Promise States

  • Pending — not settled yet
  • Fulfilled — success value available
  • Rejected — error reason available

Once settled, a Promise does not change state.

Creating a Promise

javascript
// Resolve after delay
const delayed = new Promise((resolve, reject) => {
  setTimeout(() => resolve("ok"), 100);
});
 
delayed.then((value) => console.log(value));

then / catch / finally

javascript
// Chain handlers
function fetchScore(userId) {
  return new Promise((resolve, reject) => {
    if (!userId) return reject(new Error("missing userId"));
    setTimeout(() => resolve({ userId, score: 88 }), 50);
  });
}
 
fetchScore(1)
  .then((data) => console.log("score", data.score))
  .catch((err) => console.error(err.message))
  .finally(() => console.log("done"));

Returning Promises from then

javascript
// Flatten nested async
function step1() {
  return Promise.resolve(1);
}
 
step1()
  .then((n) => {
    return Promise.resolve(n + 1);
  })
  .then((n) => console.log(n));

Promise.all and Promise.race

javascript
// Wait for all
const p1 = Promise.resolve("a");
const p2 = Promise.resolve("b");
 
Promise.all([p1, p2]).then((values) => console.log(values));
 
// First settled wins
Promise.race([
  new Promise((r) => setTimeout(() => r("slow"), 200)),
  Promise.resolve("fast"),
]).then((winner) => console.log(winner));

Promise.allSettled keeps all results even if some reject.

async / await Sugar

javascript
// async function returns a Promise
async function loadUser(id) {
  const data = await fetchScore(id);
  return { ...data, label: "player" };
}
 
loadUser(1).then((user) => console.log(user));

Use try/catch around await:

javascript
async function safeLoad(id) {
  try {
    return await fetchScore(id);
  } catch (err) {
    console.error("load failed", err.message);
    return null;
  }
}

Mini Example: Sequential Steps with await

javascript
function wait(ms, value) {
  return new Promise((resolve) => setTimeout(() => resolve(value), ms));
}
 
async function pipeline() {
  const a = await wait(30, "fetch");
  const b = await wait(30, "parse");
  const c = await wait(30, "save");
  return [a, b, c];
}
 
pipeline().then((steps) => console.log(steps.join(" → ")));

FAQ

Promise vs callback?

Promises standardize error propagation and composition; callbacks are still used at the lowest layers.

Forgot return in then?

Next then receives undefined—return values or Promises explicitly.

Unhandled rejection?

Node and browsers warn or crash on unhandled reject—always .catch or try/catch with await.

What comes next?

Property descriptors (metaprogramming), then web fundamentals.