Explorer
JavaScript

Promises Advanced: Combinators and Patterns

JavaScript Theory & Concepts

Promises Advanced: Combinators and Patterns

Promise.all, allSettled, race, any, concurrency pooling, and retry with exponential backoff.

📖 The Story & Real-World Analogy

The Four Olympic Team Relay Events

"Imagine four distinct Olympic athletic events: 1. **Promise.all (Synchronized Diving Team)**: All divers must execute their dive flawlessly. If even one diver slips, the entire team fails immediately (Fast-Fail)! 2. **Promise.allSettled (The Marathon)**: All runners run until they either cross the finish line or retire. At the end, the judges receive a complete census report of everyone who finished and everyone who dropped out. 3. **Promise.race (The 100-Meter Sprint)**: Whoever crosses the finish line first wins, whether they win a gold medal (resolve) or crash over the hurdles (reject)! 4. **Promise.any (The Search and Rescue Team)**: Three rescue teams are dispatched. You only need the FIRST team to successfully find the survivor. You only report disaster if ALL teams fail!"

Promise combinators coordinate multiple concurrent operations. Choosing the right combinator prevents silent drops, improves user experience, and optimizes throughput.

⚙️ How It Works Under The Hood (Step-by-Step)
1

1. Promise.all([p1, p2])

Fails fast: rejects immediately if ANY promise rejects. Resolves with an array of values when ALL promises fulfill. Best for dependent, all-or-nothing operations.

2

2. Promise.allSettled([p1, p2])

Never rejects early. Waits for all promises to finish and returns an array of outcome objects: `{ status: "fulfilled", value }` or `{ status: "rejected", reason }`.

3

3. Promise.race([p1, p2])

Settles as soon as the FIRST promise settles (whether fulfilled OR rejected). Ideal for implementing network timeouts.

4

4. Promise.any([p1, p2])

Resolves as soon as the FIRST promise fulfills (ignores rejections). Only rejects if ALL promises reject, throwing an `AggregateError`.

5

Retry Pattern with Exponential Backoff

Automatically retries failed network calls with progressively longer delays (2N × \text{base} + \text{jitter}) to prevent overloading recovering servers.

💻 Interactive Code Walkthrough

Building a network timeout with Promise.race and retry with exponential backoff:

JAVASCRIPT
// 1. Timeout Pattern with Promise.race
function withTimeout(promise, ms) {
  const timeout = new Promise((_, reject) =>
    setTimeout(() => reject(new Error(`Request timed out after ${ms}ms`)), ms)
  );
  return Promise.race([promise, timeout]);
}

// 2. Retry with Exponential Backoff
async function retryWithBackoff(fn, retries = 3, delay = 50) {
  try {
    return await fn();
  } catch (err) {
    if (retries <= 0) throw err;
    console.log(`Attempt failed, retrying in ${delay}ms...`);
    await new Promise(res => setTimeout(res, delay));
    return retryWithBackoff(fn, retries - 1, delay * 2);
  }
}

// Simulating unstable API
let attempt = 0;
const unstableApi = () => new Promise((res, reject) => {
  attempt++;
  attempt < 3 ? reject(new Error("503 Service Unavailable")) : res("Success on attempt 3!");
});

retryWithBackoff(unstableApi).then(msg => console.log("Final:", msg));
Console Output:
CODE
Attempt failed, retrying in 50ms...
Attempt failed, retrying in 100ms...
Final: Success on attempt 3!
⚠️ Common Pitfalls & Interview Traps
Trap
Using Promise.all for Independent Operations

The Risk: Using `Promise.all` to upload 10 user avatar images: if image #9 fails due to a network blip, the entire batch rejects, losing the other 9 successful uploads.

The Fix: Use `Promise.allSettled()` so partial successes can be kept and only failed items retried.

⚡ 30-Second Quick Revision Cheat Sheet (TL;DR)
  • ✓ `Promise.all`: All succeed or first to reject (fast-fail).
  • ✓ `Promise.allSettled`: Waits for all; returns array of `{ status, value/reason }`.
  • ✓ `Promise.race`: First to settle (either fulfill OR reject). Perfect for timeouts.
  • ✓ `Promise.any`: First to fulfill; rejects only if all reject (`AggregateError`).
  • ✓ Use exponential backoff with jitter for resilient network retries.

Finished this lesson?

Mark this chapter complete to update your learning streak and unlock the next lesson.