|

JavaScript 42 🧬 Promises

const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('done'), 1000);
});

promise.then(value => {
  console.log('Success:', value);
});

const failing = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error('failed')), 1000);
});

failing.catch(err => {
  console.log('Error:', err.message);
});

fetch('https://api.example.com/data')
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error(err));

Promise.all([p1, p2, p3]).then(results => {
  console.log(results);
});

Promise.allSettled([p1, p2, p3]).then(results => {
  results.forEach(r => console.log(r.status));
});

Promise.race([p1, p2]).then(first => {
  console.log('First:', first);
});

Promise.any([p1, p2]).then(firstSuccess => {
  console.log('First success:', firstSuccess);
});

A Promise is JavaScript’s way of representing a value that isn’t available yet but will be — or won’t be — at some point in the future. It’s the foundation of modern asynchronous code, and it solves the “callback hell” problem that plagued JavaScript before ES6.

Key point: A Promise is an object with three possible states: pending, fulfilled, or rejected. Once settled (fulfilled or rejected), a Promise is immutable — it can never change state again. You attach callbacks with .then(), .catch(), and .finally() to react to the outcome.


a – What is a Promise

A Promise represents the eventual result of an asynchronous operation. It’s a placeholder for a value that may not exist yet.

The three states:

StateMeaning
PendingThe operation hasn’t finished
FulfilledThe operation succeeded — has a value
RejectedThe operation failed — has a reason (usually an Error)

Once a Promise is settled (fulfilled or rejected), it stays that way forever.

State transitions:

┌──────────────────────────────────────────────┐
│           Promise states                     │
│                                              │
│              ┌──────────┐                    │
│              │ pending  │                    │
│              └────┬─────┘                    │
│                   │                          │
│          ┌────────┴────────┐                 │
│          │                 │                 │
│          ▼                 ▼                 │
│    ┌───────────┐    ┌────────────┐           │
│    │ fulfilled │    │  rejected  │           │
│    └───────────┘    └────────────┘           │
│                                              │
│    settled — never changes again             │
│                                              │
└──────────────────────────────────────────────┘

Creating a Promise:

const promise = new Promise((resolve, reject) => {
  // async work here
  if (success) {
    resolve(value);
  } else {
    reject(new Error('reason'));
  }
});

The executor function runs immediately and synchronously. Inside it, you call resolve() or reject() when the async work completes.

A simple example:

const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('done'), 1000);
});

promise.then(value => {
  console.log('Success:', value);
});
// (after 1 second)
// [ Success: done ]

A failing Promise:

const failing = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error('failed')), 1000);
});

failing.catch(err => {
  console.log('Error:', err.message);
});
// (after 1 second)
// [ Error: failed ]

Why Promises matter:

  • No callback hell — chain with .then() instead of nesting
  • Error handling.catch() catches any failure in the chain
  • ComposabilityPromise.all, Promise.race, etc.
  • Cleaner async — the foundation for async/await
  • Standard — built into the language, no library needed

Promise vs callback:

// ❌ Callback style — nested, hard to read
getUser(id, (user) => {
  getOrders(user.id, (orders) => {
    getDetails(orders[0].id, (details) => {
      console.log(details);
    });
  });
});

// ✅ Promise style — flat, chainable
getUser(id)
  .then(user => getOrders(user.id))
  .then(orders => getDetails(orders[0].id))
  .then(details => console.log(details))
  .catch(err => console.error(err));

A Promise is not a value — it’s a container:

const p = Promise.resolve(42);
console.log(p);
// [ Promise { 42 } ]

// To get the value, use .then() or await
p.then(v => console.log(v));
// [ 42 ]

Logging a Promise shows its state and value — but you can’t read the value directly.


b – Promise methods and chaining

Promises have three instance methods for reacting to their outcome, plus several static methods for combining Promises.

Instance methods:

MethodPurpose
.then(onFulfilled, onRejected)Handle success (and optionally failure)
.catch(onRejected)Handle failure only
.finally(onFinally)Run cleanup regardless of outcome

.then() — handle success:

Promise.resolve(42).then(value => {
  console.log(value);
});
// [ 42 ]

Chaining .then():

Each .then() returns a new Promise, which lets you chain:

Promise.resolve(1)
  .then(v => v + 1)
  .then(v => v * 2)
  .then(v => console.log(v));
// [ 4 ]

The return value of one .then() becomes the input to the next.

Returning a Promise from .then():

fetch('/user')
  .then(res => res.json())      // returns a Promise
  .then(user => fetch(`/orders/${user.id}`))
  .then(res => res.json())
  .then(orders => console.log(orders));

The chain waits for each Promise to resolve.

.catch() — handle failure:

Promise.reject(new Error('oops'))
  .catch(err => {
    console.log('Caught:', err.message);
  });
// [ Caught: oops ]

.catch() is shorthand for .then(null, onRejected).

.catch() catches errors from anywhere in the chain:

Promise.resolve(1)
  .then(v => v + 1)
  .then(() => { throw new Error('mid-chain'); })
  .then(v => console.log(v))     // skipped
  .catch(err => console.log('Caught:', err.message));
// [ Caught: mid-chain ]

Any error thrown in .then() skips to the next .catch().

.finally() — always runs:

showSpinner();
fetch('/data')
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error(err))
  .finally(() => hideSpinner());

.finally() doesn’t receive the value or the error — it just runs cleanup.

Chaining pattern — the full flow:

Promise.resolve(1)
  .then(v => {
    console.log('Step 1:', v);
    return v + 1;
  })
  .then(v => {
    console.log('Step 2:', v);
    return v + 1;
  })
  .catch(err => {
    console.log('Error:', err.message);
  })
  .finally(() => {
    console.log('Done');
  });
// [ Step 1: 1 ]
// [ Step 2: 2 ]
// [ Done ]

Return values propagate:

Promise.resolve(2)
  .then(v => v * 10)
  .then(v => v + 1)
  .then(v => console.log(v));
// [ 21 ]

Async functions return Promises automatically:

async function getData() {
  return 42;
}

getData().then(v => console.log(v));
// [ 42 ]

Static methods for combining Promises:

MethodPurpose
Promise.all(iterable)Wait for all — reject if any fails
Promise.allSettled(iterable)Wait for all, never rejects
Promise.race(iterable)Settle with the first to finish
Promise.any(iterable)Resolve with the first success
Promise.resolve(value)Wrap a value in a resolved Promise
Promise.reject(reason)Create a rejected Promise

Promise.all — wait for all, fail fast:

Promise.all([
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
]).then(values => {
  console.log(values);
});
// [ [ 1, 2, 3 ] ]

If any rejects, the whole thing rejects:

Promise.all([
  Promise.resolve(1),
  Promise.reject(new Error('fail')),
  Promise.resolve(3)
]).catch(err => console.log(err.message));
// [ fail ]

Promise.allSettled — wait for all, never rejects:

Promise.allSettled([
  Promise.resolve(1),
  Promise.reject(new Error('fail')),
  Promise.resolve(3)
]).then(results => {
  console.log(results);
});
// [
//   { status: 'fulfilled', value: 1 },
//   { status: 'rejected', reason: Error: fail },
//   { status: 'fulfilled', value: 3 }
// ]

Promise.race — first to settle wins:

Promise.race([
  new Promise(r => setTimeout(() => r('slow'), 1000)),
  new Promise(r => setTimeout(() => r('fast'), 100))
]).then(winner => console.log(winner));
// [ fast ]

The first Promise to settle (fulfill or reject) wins.

Promise.any — first success wins:

Promise.any([
  Promise.reject(new Error('a')),
  Promise.resolve('b'),
  Promise.resolve('c')
]).then(first => console.log(first));
// [ b ]

It ignores rejections unless all reject.

Comparison table:

MethodWaits forRejects when
allAllAny rejects
allSettledAllNever
raceFirst to settleFirst rejects
anyFirst to fulfillAll reject

Promise.resolve and Promise.reject:

Promise.resolve(42).then(v => console.log(v));
// [ 42 ]

Promise.reject(new Error('x')).catch(e => console.log(e.message));
// [ x ]

Useful for testing and for normalizing values into Promises.

A practical example — fetch multiple resources:

Promise.all([
  fetch('/user').then(r => r.json()),
  fetch('/orders').then(r => r.json()),
  fetch('/products').then(r => r.json())
]).then(([user, orders, products]) => {
  console.log('User:', user);
  console.log('Orders:', orders);
  console.log('Products:', products);
});

All three fetches run in parallel. The .then() receives an array of results.

Error handling in chains:

fetch('/data')
  .then(res => {
    if (!res.ok) throw new Error('HTTP ' + res.status);
    return res.json();
  })
  .then(data => console.log(data))
  .catch(err => console.error('Failed:', err.message))
  .finally(() => console.log('Done'));

c – Common Promise patterns

Promises enable several recurring patterns that come up constantly in real code.

Pattern 1 — Sequential execution:

async function sequential() {
  const a = await step1();
  const b = await step2(a);
  const c = await step3(b);
  return c;
}

Each step waits for the previous one.

Pattern 2 — Parallel execution:

async function parallel() {
  const [a, b, c] = await Promise.all([
    step1(),
    step2(),
    step3()
  ]);
  return [a, b, c];
}

All three run at the same time.

Pattern 3 — Racing with timeout:

function withTimeout(promise, ms) {
  const timeout = new Promise((_, reject) =>
    setTimeout(() => reject(new Error('Timeout')), ms)
  );
  return Promise.race([promise, timeout]);
}

withTimeout(fetch('/slow'), 5000)
  .then(res => console.log(res))
  .catch(err => console.log(err.message));

Pattern 4 — Retry on failure:

async function retry(fn, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fn();
    } catch (err) {
      if (i === attempts - 1) throw err;
      console.log(`Attempt ${i + 1} failed, retrying...`);
    }
  }
}

retry(() => fetch('/flaky')).catch(err => console.log(err));

Pattern 5 — Fallback to default:

function withFallback(promise, fallback) {
  return promise.catch(() => fallback);
}

withFallback(fetch('/data').then(r => r.json()), {})
  .then(data => console.log(data));

Pattern 6 — Promisifying callbacks:

function promisify(fn) {
  return (...args) =>
    new Promise((resolve, reject) => {
      fn(...args, (err, result) => {
        if (err) reject(err);
        else resolve(result);
      });
    });
}

const readFile = promisify(require('fs').readFile);
readFile('/etc/passwd', 'utf8')
  .then(content => console.log(content))
  .catch(err => console.log(err));

Pattern 7 — Loading all, ignoring failures:

Promise.allSettled(urls.map(u => fetch(u)))
  .then(results => {
    const successes = results.filter(r => r.status === 'fulfilled');
    const failures = results.filter(r => r.status === 'rejected');
    console.log(`${successes.length} succeeded, ${failures.length} failed`);
  });

Pattern 8 — Racing multiple sources:

Promise.any([
  fetch('/api/primary').then(r => r.json()),
  fetch('/api/backup').then(r => r.json())
]).then(data => console.log('Got from fastest:', data));

Pattern 9 — Limiting concurrency:

async function mapLimit(items, limit, fn) {
  const results = [];
  for (let i = 0; i < items.length; i += limit) {
    const chunk = items.slice(i, i + limit);
    results.push(...await Promise.all(chunk.map(fn)));
  }
  return results;
}

Pattern 10 — Cancelling via race:

let cancelled = false;
const promise = fetch('/data');

Promise.race([
  promise,
  new Promise((_, reject) =>
    setTimeout(() => {
      cancelled = true;
      reject(new Error('Cancelled'));
    }, 1000)
  )
]).catch(err => console.log(err.message));

Pattern 11 — Await multiple without blocking:

const p1 = fetch('/a');
const p2 = fetch('/b');
const p3 = fetch('/c');

const [a, b, c] = await Promise.all([p1, p2, p3]);

Start them all first, then await together.

Pattern 12 — Converting callback APIs:

const { promisify } = require('util');
const readFile = promisify(require('fs').readFile);
const data = await readFile('/etc/passwd', 'utf8');

Node.js has a built-in promisify.

A complete example — parallel with error handling:

async function loadDashboard(userId) {
  const results = await Promise.allSettled([
    fetch(`/user/${userId}`).then(r => r.json()),
    fetch(`/user/${userId}/orders`).then(r => r.json()),
    fetch(`/user/${userId}/messages`).then(r => r.json())
  ]);

  const [user, orders, messages] = results.map(r =>
    r.status === 'fulfilled' ? r.value : null
  );

  return { user, orders, messages };
}

Common patterns summary:

PatternUse
SequentialEach step depends on the previous
ParallelIndependent tasks
TimeoutRace against a timer
RetryRe-attempt on failure
FallbackProvide default on error
PromisifyWrap callback APIs
allSettledHandle partial failures
anyFastest success wins
raceFirst result (success or fail)

Complete Example Session

// ============================================
// PART 1: CREATING A PROMISE
// ============================================

const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('done'), 1000);
});

promise.then(value => {
  console.log('Success:', value);
});
// (after 1s)
// [ Success: done ]

// ============================================
// PART 2: REJECTED PROMISE
// ============================================

const failing = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error('failed')), 1000);
});

failing.catch(err => {
  console.log('Error:', err.message);
});
// (after 1s)
// [ Error: failed ]

// ============================================
// PART 3: CHAINING .THEN
// ============================================

Promise.resolve(1)
  .then(v => v + 1)
  .then(v => v * 2)
  .then(v => console.log(v));
// [ 4 ]

// ============================================
// PART 4: RETURNING PROMISES
// ============================================

Promise.resolve(1)
  .then(v => Promise.resolve(v + 1))
  .then(v => console.log(v));
// [ 2 ]

// ============================================
// PART 5: THROW IN CHAIN
// ============================================

Promise.resolve(1)
  .then(v => { throw new Error('mid-chain'); })
  .then(v => console.log(v))
  .catch(err => console.log('Caught:', err.message));
// [ Caught: mid-chain ]

// ============================================
// PART 6: FINALLY
// ============================================

Promise.resolve('ok')
  .then(v => console.log(v))
  .catch(err => console.log(err))
  .finally(() => console.log('Done'));
// [ ok ]
// [ Done ]

// ============================================
// PART 7: PROMISE.ALL
// ============================================

Promise.all([
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
]).then(values => console.log(values));
// [ [ 1, 2, 3 ] ]

// ============================================
// PART 8: PROMISE.ALL WITH FAILURE
// ============================================

Promise.all([
  Promise.resolve(1),
  Promise.reject(new Error('fail')),
  Promise.resolve(3)
]).catch(err => console.log(err.message));
// [ fail ]

// ============================================
// PART 9: PROMISE.ALLSETTLED
// ============================================

Promise.allSettled([
  Promise.resolve(1),
  Promise.reject(new Error('fail')),
  Promise.resolve(3)
]).then(results => {
  console.log(results.map(r => r.status));
});
// [ [ 'fulfilled', 'rejected', 'fulfilled' ] ]

// ============================================
// PART 10: PROMISE.RACE
// ============================================

Promise.race([
  new Promise(r => setTimeout(() => r('slow'), 1000)),
  new Promise(r => setTimeout(() => r('fast'), 100))
]).then(winner => console.log(winner));
// [ fast ]

// ============================================
// PART 11: PROMISE.ANY
// ============================================

Promise.any([
  Promise.reject(new Error('a')),
  Promise.resolve('b'),
  Promise.resolve('c')
]).then(first => console.log(first));
// [ b ]

// ============================================
// PART 12: PROMISE.RESOLVE / REJECT
// ============================================

Promise.resolve(42).then(v => console.log(v));
// [ 42 ]

Promise.reject(new Error('x')).catch(e => console.log(e.message));
// [ x ]

// ============================================
// PART 13: PROMISIFY
// ============================================

function promisify(fn) {
  return (...args) =>
    new Promise((resolve, reject) => {
      fn(...args, (err, result) => {
        if (err) reject(err);
        else resolve(result);
      });
    });
}

// ============================================
// PART 14: SEQUENTIAL
// ============================================

async function sequential() {
  const a = await Promise.resolve(1);
  const b = await Promise.resolve(a + 1);
  const c = await Promise.resolve(b + 1);
  return c;
}

sequential().then(v => console.log(v));
// [ 3 ]

// ============================================
// PART 15: PARALLEL
// ============================================

async function parallel() {
  const [a, b, c] = await Promise.all([
    Promise.resolve(1),
    Promise.resolve(2),
    Promise.resolve(3)
  ]);
  return [a, b, c];
}

parallel().then(v => console.log(v));
// [ [ 1, 2, 3 ] ]

// ============================================
// PART 16: TIMEOUT PATTERN
// ============================================

function withTimeout(promise, ms) {
  const timeout = new Promise((_, reject) =>
    setTimeout(() => reject(new Error('Timeout')), ms)
  );
  return Promise.race([promise, timeout]);
}

withTimeout(
  new Promise(r => setTimeout(() => r('done'), 2000)),
  500
).catch(err => console.log(err.message));
// [ Timeout ]

// ============================================
// PART 17: RETRY PATTERN
// ============================================

async function retry(fn, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fn();
    } catch (err) {
      if (i === attempts - 1) throw err;
    }
  }
}

// ============================================
// PART 18: FALLBACK PATTERN
// ============================================

function withFallback(promise, fallback) {
  return promise.catch(() => fallback);
}

withFallback(Promise.reject(new Error('x')), 'default')
  .then(v => console.log(v));
// [ default ]

// ============================================
// PART 19: MAP WITH CONCURRENCY
// ============================================

async function mapLimit(items, limit, fn) {
  const results = [];
  for (let i = 0; i < items.length; i += limit) {
    const chunk = items.slice(i, i + limit);
    results.push(...await Promise.all(chunk.map(fn)));
  }
  return results;
}

mapLimit([1, 2, 3, 4, 5], 2, x => Promise.resolve(x * 10))
  .then(r => console.log(r));
// [ [ 10, 20, 30, 40, 50 ] ]

// ============================================
// PART 20: FULL SCRIPT
// ============================================

const promise42 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('done'), 1000);
});

promise42.then(value => {
  console.log('Success:', value);
});

const failing42 = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error('failed')), 1000);
});

failing42.catch(err => {
  console.log('Error:', err.message);
});

Promise.all([
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
]).then(values => console.log(values));

Promise.allSettled([
  Promise.resolve(1),
  Promise.reject(new Error('fail'))
]).then(results => console.log(results.map(r => r.status)));

Promise.race([
  Promise.resolve('fast'),
  new Promise(r => setTimeout(() => r('slow'), 100))
]).then(winner => console.log(winner));

Promise.any([
  Promise.reject(new Error('a')),
  Promise.resolve('b')
]).then(first => console.log(first));

Quick Reference

Promise States

StateMeaning
pendingNot settled yet
fulfilledResolved successfully
rejectedFailed with a reason

Instance Methods

MethodPurpose
.then(onFulfilled, onRejected)Handle success/failure
.catch(onRejected)Handle failure
.finally(onFinally)Always runs

Static Methods

MethodPurpose
Promise.resolve(v)Wrap value in resolved Promise
Promise.reject(e)Create rejected Promise
Promise.all(arr)All succeed or reject on first failure
Promise.allSettled(arr)Wait for all, never rejects
Promise.race(arr)First to settle wins
Promise.any(arr)First to fulfill wins

Combinators

MethodResolvesRejects
allWhen all fulfillWhen any rejects
allSettledWhen all settleNever
raceFirst to fulfillFirst to reject
anyFirst to fulfillWhen all reject

Common Patterns

PatternCode
Sequentialawait a; await b; await c;
Parallelawait Promise.all([a, b, c])
TimeoutPromise.race([fn(), timeout])
RetryLoop with try/catch
Fallbackpromise.catch(() => fallback)
Promisifynew Promise((res, rej) => fn(...))

Chaining Rules

Return from .then()Next .then() receives
ValueThat value
PromiseResolved value of that Promise
Throw errorSkips to .catch()
(nothing)undefined

Errors in Chains

Where thrownWhere caught
In executor.catch() on that Promise
In .then()Next .catch()
In .catch()Next .catch()
In .finally()Next .catch()

Best Practices

Do This:

// Always add .catch()
fetch('/data')
  .then(r => r.json())
  .catch(err => console.error(err));           // ✅

// Use Promise.all for parallel
const [a, b] = await Promise.all([fa(), fb()]); // ✅

// Use allSettled for partial failure
const results = await Promise.allSettled(tasks); // ✅

// Use .finally for cleanup
promise.finally(() => hideSpinner());          // ✅

// Return Promises from .then for chaining
.then(user => fetch(`/orders/${user.id}`))     // ✅

// Use Promise.race for timeouts
Promise.race([fn(), timeout(ms)]);             // ✅

// Use Promise.any for fallback sources
Promise.any([primary, backup]);                // ✅

// Prefer async/await for readability
async function run() {
  try { await fn(); } catch (e) { ... }
}                                              // ✅

Don’t Do This:

// Don't forget .catch()
fetch('/data').then(r => r.json());            // ❌ unhandled rejection

// Don't nest .then() unnecessarily
promise.then(a =>
  b().then(b => c().then(c => ...))
);                                              // ❌ use chaining
promise.then(a => b()).then(b => c()).then(c => ...);  // ✅

// Don't create a Promise around an existing Promise
new Promise((res, rej) => fetch('/x').then(res, rej));  // ❌ anti-pattern

// Don't use the Promise constructor for sync code
new Promise(r => r(42));                       // ❌ use Promise.resolve

// Don't mix callbacks and Promises
fn((err, res) => { ... }).then(...);           // ❌ pick one

// Don't ignore the returned Promise
array.forEach(async x => await process(x));    // ❌ not awaited
await Promise.all(array.map(process));         // ✅

// Don't throw inside .then without .catch
promise.then(() => { throw new Error('x'); }); // ❌ unhandled
promise.then(() => { throw new Error('x'); }).catch(e => ...);  // ✅

// Don't rely on .finally receiving the value
promise.finally(v => console.log(v));          // ❌ v is undefined

Common Pitfalls

PitfallProblemSolution
No .catch()Unhandled rejectionAlways catch
Nested .then()Callback hell returnsFlatten the chain
Promise constructor overuseAnti-patternUse async
forEach with asyncDoesn’t awaitfor...of or map
Missing awaitPromise not settledawait or .then()
finally gets no valueDoesn’t receive resultCapture before finally
all fails fastOne failure = all failUse allSettled
race on rejectRejects if first rejectsUse any for first success
Floating promiseSilent failurevoid or .catch()
Returning non-PromiseChain works but oddPromise.resolve

Real-World Examples

1. Basic Promise

const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('done'), 1000);
});

promise.then(value => {
  console.log('Success:', value);
});
// [ Success: done ]

2. Rejected Promise

const failing = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error('failed')), 1000);
});

failing.catch(err => {
  console.log('Error:', err.message);
});
// [ Error: failed ]

3. Chaining

Promise.resolve(1)
  .then(v => v + 1)
  .then(v => v * 2)
  .then(v => console.log(v));
// [ 4 ]

4. Error in Chain

Promise.resolve(1)
  .then(v => { throw new Error('mid'); })
  .then(v => console.log(v))
  .catch(err => console.log(err.message));
// [ mid ]

5. Finally

Promise.resolve('ok')
  .then(v => console.log(v))
  .finally(() => console.log('Done'));
// [ ok ]
// [ Done ]

6. Promise.all

Promise.all([1, 2, 3].map(x => Promise.resolve(x * 2)))
  .then(values => console.log(values));
// [ [ 2, 4, 6 ] ]

7. Promise.allSettled

Promise.allSettled([
  Promise.resolve(1),
  Promise.reject(new Error('fail'))
]).then(results => {
  console.log(results[0].status);  // fulfilled
  console.log(results[1].status);  // rejected
});

8. Promise.race

Promise.race([
  new Promise(r => setTimeout(() => r('slow'), 1000)),
  new Promise(r => setTimeout(() => r('fast'), 100))
]).then(winner => console.log(winner));
// [ fast ]

9. Promise.any

Promise.any([
  Promise.reject(new Error('a')),
  Promise.resolve('b')
]).then(first => console.log(first));
// [ b ]

10. Promise.resolve

Promise.resolve(42).then(v => console.log(v));
// [ 42 ]

11. Promise.reject

Promise.reject(new Error('x')).catch(e => console.log(e.message));
// [ x ]

12. Fetch with Promise

fetch('https://api.example.com/data')
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error(err));

13. Timeout Pattern

function withTimeout(promise, ms) {
  const timeout = new Promise((_, reject) =>
    setTimeout(() => reject(new Error('Timeout')), ms)
  );
  return Promise.race([promise, timeout]);
}

withTimeout(fetch('/slow'), 5000)
  .then(res => console.log(res))
  .catch(err => console.log(err.message));

14. Retry Pattern

async function retry(fn, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fn();
    } catch (err) {
      if (i === attempts - 1) throw err;
    }
  }
}

15. Parallel with Concurrency

async function mapLimit(items, limit, fn) {
  const results = [];
  for (let i = 0; i < items.length; i += limit) {
    const chunk = items.slice(i, i + limit);
    results.push(...await Promise.all(chunk.map(fn)));
  }
  return results;
}

16. Fallback Pattern

withFallback(Promise.reject(new Error('x')), 'default')
  .then(v => console.log(v));
// [ default ]

17. Promisify

function promisify(fn) {
  return (...args) =>
    new Promise((resolve, reject) => {
      fn(...args, (err, result) => {
        if (err) reject(err);
        else resolve(result);
      });
    });
}

18. Parallel Data Load

async function loadAll() {
  const [user, orders, products] = await Promise.all([
    fetch('/user').then(r => r.json()),
    fetch('/orders').then(r => r.json()),
    fetch('/products').then(r => r.json())
  ]);
  return { user, orders, products };
}

19. Sequential Data Load

async function loadSequential() {
  const user = await fetch('/user').then(r => r.json());
  const orders = await fetch(`/orders/${user.id}`).then(r => r.json());
  const details = await fetch(`/orders/${orders[0].id}`).then(r => r.json());
  return details;
}

20. Full Script

const promise42 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('done'), 1000);
});

promise42.then(value => {
  console.log('Success:', value);
});

const failing42 = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error('failed')), 1000);
});

failing42.catch(err => {
  console.log('Error:', err.message);
});

fetch('https://api.example.com/data')
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error(err));

Promise.all([p1, p2, p3]).then(results => {
  console.log(results);
});

Promise.allSettled([p1, p2, p3]).then(results => {
  results.forEach(r => console.log(r.status));
});

Promise.race([p1, p2]).then(first => {
  console.log('First:', first);
});

Promise.any([p1, p2]).then(firstSuccess => {
  console.log('First success:', firstSuccess);
});

Visual: Promise Lifecycle

┌──────────────────────────────────────────────┐
│           Promise lifecycle                  │
│                                              │
│  new Promise((resolve, reject) => {          │
│    // async work                             │
│  })                                          │
│         │                                    │
│         ▼                                    │
│  ┌──────────┐                                │
│  │ pending  │                                │
│  └────┬─────┘                                │
│       │                                      │
│   ┌───┴───┐                                  │
│   │       │                                  │
│   ▼       ▼                                  │
│  fulfill  reject                             │
│   │       │                                  │
│   ▼       ▼                                  │
│  .then()  .catch()                           │
│   │       │                                  │
│   └───┬───┘                                  │
│       │                                      │
│       ▼                                      │
│  .finally()  — always runs                   │
│                                              │
└──────────────────────────────────────────────┘

Visual: Promise Chaining

┌──────────────────────────────────────────────┐
│           Chained .then()                    │
│                                              │
│  Promise.resolve(1)                          │
│       │                                      │
│       ▼                                      │
│  .then(v => v + 1)  →  returns Promise(2)    │
│       │                                      │
│       ▼                                      │
│  .then(v => v * 2)  →  returns Promise(4)    │
│       │                                      │
│       ▼                                      │
│  .then(v => console.log(v))  →  4            │
│       │                                      │
│       ▼                                      │
│  .catch(err => ...)  →  skipped if no error  │
│       │                                      │
│       ▼                                      │
│  .finally(() => ...)  →  always runs         │
│                                              │
└──────────────────────────────────────────────┘

Visual: Combinators

┌──────────────────────────────────────────────┐
│  Promise.all([a, b, c])                      │
│                                              │
│  a  ────►  ✓                                 │
│  b  ────►  ✓                                 │
│  c  ────►  ✗  → whole thing rejects          │
│                                              │
│  Result: reject on FIRST failure             │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│  Promise.allSettled([a, b, c])               │
│                                              │
│  a  ────►  ✓                                 │
│  b  ────►  ✗                                 │
│  c  ────►  ✓                                 │
│                                              │
│  Result: array of {status, value|reason}     │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│  Promise.race([a, b])                        │
│                                              │
│  a  ────►  slow (100ms)                      │
│  b  ────►  fast (10ms)  ← winner             │
│                                              │
│  Result: first to settle                     │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│  Promise.any([a, b, c])                      │
│                                              │
│  a  ────►  ✗                                 │
│  b  ────►  ✓  ← first success                │
│  c  ────►  (still pending)                   │
│                                              │
│  Result: first to SUCCEED                    │
│                                              │
└──────────────────────────────────────────────┘

Summary

ConceptSyntaxExample
Createnew Promise((res, rej) => {})new Promise(r => r(42))
Resolveresolve(value)resolve('done')
Rejectreject(err)reject(new Error('x'))
Success.then(fn)p.then(v => ...)
Failure.catch(fn)p.catch(e => ...)
Cleanup.finally(fn)p.finally(() => ...)
AllPromise.all(arr)All or fail
All settledPromise.allSettled(arr)Always array
RacePromise.race(arr)First to settle
AnyPromise.any(arr)First success
ResolvePromise.resolve(v)Wrap value
RejectPromise.reject(e)Rejected Promise

Key takeaways:

  • A Promise represents a value that will exist in the future
  • It has three states: pending, fulfilled, rejected — and once settled, never changes
  • The executor runs immediately; resolve and reject settle the Promise
  • .then() handles success; .catch() handles failure; .finally() always runs
  • Chaining returns a new Promise — return values propagate
  • Throwing inside .then() skips to the next .catch()
  • Promise.all waits for all or rejects on the first failure
  • Promise.allSettled never rejects — gives you an array of results
  • Promise.race settles with the first Promise
  • Promise.any resolves with the first success, rejects only if all fail
  • Promise.resolve and Promise.reject wrap values
  • Always add .catch() — unhandled rejections are bugs
  • Use async/await for cleaner syntax on top of Promises
  • Promises are the foundation of modern async JavaScript — master them

Remember: A Promise is a container for a future value. Create it, chain it, catch it, clean it up. Use Promise.all for parallel, allSettled for tolerant, race for timing, any for fastest success. Never forget .catch(). Never nest .then(). Always return from .then() when chaining. Master Promises, and the async world opens up — including async/await, which is built on top of them.


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!