A Horror Story About JavaScript Promise

Published: (March 1, 2026 at 06:11 AM EST)
8 min read
Source: Dev.to

Source: Dev.to

Before the Midnight Adventure – What’s a Promise?

“Don’t worry – it’s easier than facing a monster under the bed!”

A Promise is an object that represents the eventual completion (or failure) of an asynchronous operation.

Real‑life analogy:
Your friend promises to bring you coffee. Right now you don’t have it – the promise is pending. Later you either get the coffee (fulfilled) or your friend calls to say they spilled it (rejected).

In JavaScript a Promise is created with the new Promise() constructor, which receives a function with two parameters: resolve and reject.

const coffeePromise = new Promise((resolve, reject) => {
    // Simulate making coffee
    const success = true;
    if (success) {
        resolve("☕ Here's your coffee!");
    } else {
        reject("💔 Spilled the coffee...");
    }
});

Handling the result

  • .then() runs when the Promise is fulfilled and receives the resolved value.
  • .catch() runs when the Promise is rejected and receives the error.
coffeePromise
    .then(message => {
        console.log(message); // "☕ Here's your coffee!"
    })
    .catch(error => {
        console.log(error);   // "💔 Spilled the coffee..."
    });

You can chain multiple .then() calls, but we’ll keep it simple for now.

The 3:34 AM Bathroom Trip – A Promise Analogy

It’s 3:34 AM. Your bladder is screaming like a DDoS attack. You need to get to the bathroom, but:

  • You live alone.
  • Grandmother’s stories say ghosts roam after 3 AM.
  • Monsters under the bed are most active.
  • The hallway feels like a road to hell.

You’re frozen, weighing two options:

  1. Wet the bed
  2. Face the darkness (supernatural beings)

This is exactly like handling multiple promises in JavaScript.

The three conditions you need

  1. Flip the hallway switch – hope it works.
  2. Flip the bathroom light – hope it works.
  3. Check under the bed – hope there’s no monster salivating at you.
// Hallway light
const hallwayLight = new Promise((resolve, reject) => {
    const bulbWorks = Math.random() > 0.3; // 70 % chance it works
    setTimeout(() => {
        if (bulbWorks) {
            resolve("💡 Hallway light is ON");
        } else {
            reject("💀 Hallway light bulb is dead");
        }
    }, 1000);
});

// Bathroom light
const bathroomLight = new Promise((resolve, reject) => {
    const bulbWorks = Math.random() > 0.2; // 80 % chance it works
    setTimeout(() => {
        if (bulbWorks) {
            resolve("🚽 Bathroom light is ON");
        } else {
            reject("👻 Bathroom light is dead");
        }
    }, 1500);
});

// Under‑bed check
const underBedCheck = new Promise((resolve, reject) => {
    const monsterPresent = Math.random() > 0.6; // 40 % chance of monster
    setTimeout(() => {
        if (!monsterPresent) {
            resolve("🛏️ Under the bed is CLEAR");
        } else {
            reject("👹 MONSTER under the bed!");
        }
    }, 2000);
});

1️⃣ Promise.all()

“I will ONLY get out of bed if ALL THREE things happen. If any fail, I stay right here.”

Promise.all([hallwayLight, bathroomLight, underBedCheck])
    .then(results => {
        console.log("🎉 All systems go! Time to sprint!");
        console.log(results);
        // You get out of bed and run with tears of happiness
    })
    .catch(error => {
        console.log("😭 NOPE. Staying in bed.");
        console.log("Reason:", error);
        // You wet the bed. Game over.
    });

Possible output

Success

🎉 All systems go! Time to sprint!
['💡 Hallway light is ON', '🚽 Bathroom light is ON', '🛏️ Under the bed is CLEAR']

Failure

😭 NOPE. Staying in bed.
Reason: 💀 Hallway light bulb is dead

When to use Promise.all()

  • All API calls must succeed before rendering a page.
  • Uploading multiple files where every file must finish.

2️⃣ Promise.allSettled()

“Let me check everything first. I’ll wait until I know the status of all three safety measures, then decide based on reality.”

Promise.allSettled([hallwayLight, bathroomLight, underBedCheck])
    .then(results => {
        console.log("📋 Let's assess the situation:");
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                console.log(`✅ Promise ${index + 1}:`, result.value);
            } else {
                console.log(`❌ Promise ${index + 1}:`, result.reason);
            }
        });
        // Make a decision based on the collected information
    });

Sample output

📋 Let's assess the situation:
❌ Promise 1: 💀 Hallway light bulb is dead
✅ Promise 2: 🚽 Bathroom light is ON
✅ Promise 3: 🛏️ Under the bed is CLEAR

When to use Promise.allSettled()

  • You need the result of every promise, regardless of success or failure.
  • Logging/reporting the outcome of a batch of operations.

3️⃣ Promise.race() (optional – not in original text but often paired)

“Whichever safety measure resolves first decides my fate.”

Promise.race([hallwayLight, bathroomLight, underBedCheck])
    .then(first => {
        console.log("🏁 First result:", first);
    })
    .catch(error => {
        console.log("💥 First error:", error);
    });

When to use Promise.race()

  • Implementing timeouts.
  • Acting on the fastest response among several sources.

4️⃣ Promise.any() (optional – not in original text but completes the set)

“I’ll go as soon as any safety measure succeeds; failures are ignored until one works.”

Promise.any([hallwayLight, bathroomLight, underBedCheck])
    .then(firstSuccess => {
        console.log("🚀 First successful promise:", firstSuccess);
    })
    .catch(aggregateError => {
        console.log("❗ All promises rejected:", aggregateError);
    });

When to use Promise.any()

  • Trying multiple redundant services and proceeding with the first that works.
  • Fallback strategies where any success is sufficient.

Takeaway

  • Promise.allAll must succeed.
  • Promise.allSettledKnow the outcome of every promise.
  • Promise.raceFirst settled (fulfilled or rejected) wins.
  • Promise.anyFirst fulfilled wins; ignore rejections until one succeeds.

Armed with these tools, you can survive any 3 AM bathroom trip—or any asynchronous JavaScript challenge! 🚀

Promise Methods Illustrated with a 3 AM Horror Story

Below is a cleaned‑up version of the original markdown. The structure, emojis, and narrative are preserved, but the formatting now follows proper Markdown conventions.

1️⃣ Promise.all()

Promise.all([hallwayLight, bathroomLight, underBedCheck])
  .then((results) => {
    console.log('✅ All checks completed:');
    results.forEach((result, i) => console.log(`  ${i + 1}. ${result}`));
  })
  .catch((error) => {
    console.error('❌ One of the checks failed:', error);
  });

When to use

  • You need all operations to succeed before proceeding.
  • Example: uploading several files and you only continue if every upload succeeds.
  • Example: a batch job that must finish completely before moving on.

2️⃣ Promise.allSettled()

Promise.allSettled([hallwayLight, bathroomLight, underBedCheck])
  .then((results) => {
    console.log('📋 Full report of every operation:');
    results.forEach((result, i) => {
      if (result.status === 'fulfilled') {
        console.log(`  ${i + 1}. ✅ ${result.value}`);
      } else {
        console.log(`  ${i + 1}. ❌ ${result.reason}`);
      }
    });

    const anyLight = results.some(r =>
      r.status === 'fulfilled' &&
      (r.value.includes('light') || r.value.includes('CLEAR'))
    );

    if (anyLight) {
      console.log('🏃 Good enough! Making a run for it!');
    } else {
      console.log('😱 Complete darkness AND monsters? Staying put.');
    }
  });

When to use

  • You need the outcome of every promise, regardless of success or failure.
  • Typical scenarios:
    • Uploading multiple files and you want to know which succeeded/failed.
    • Running a batch process and you need a complete report.

3️⃣ Promise.race()

Promise.race([hallwayLight, bathroomLight, underBedCheck])
  .then((firstResult) => {
    console.log(`🏁 First thing happened: ${firstResult}`);
    console.log('🚀 Taking that as a sign! Running NOW!');
    // You sprint regardless of what the first result was
  })
  .catch((firstError) => {
    console.log(`🏁 First thing happened (and it was bad): ${firstError}`);
    console.log('😰 Oh no. That’s a bad sign. But I’m already out of bed!');
    // You’re already committed. You run into darkness.
  });

When to use

  • You need the first settled promise (fulfilled or rejected).
  • Common uses:
    • Implementing timeouts: Promise.race([actualRequest, timeoutPromise]).
    • Getting the fastest response from multiple sources.

4️⃣ Promise.any()

Promise.any([hallwayLight, bathroomLight, underBedCheck])
  .then((firstSuccess) => {
    console.log(`🎯 Found one working safety measure: ${firstSuccess}`);
    console.log('🏃 That’s enough! Making my move!');
  })
  .catch((error) => {
    console.log('💀 ALL safety measures failed!');
    console.log('Errors:', error.errors); // AggregateError
    console.log('Staying in bed forever.');
  });

When to use

  • You only need one successful result; the rest can be ignored.
  • Typical scenarios:
    • Fallback APIs (try server A, if it fails try server B).
    • Any situation where a single success is sufficient to proceed.

Quick Recap

MethodWhat it ReturnsWhen to Choose
Promise.all()All fulfilled values (or rejects on first failure)You need everything to succeed.
Promise.allSettled()Array of {status, value/reason} for every promiseYou want a full report, successes and failures.
Promise.race()First settled value or rejectionYou care about speed, not completeness.
Promise.any()First fulfilled value (or AggregateError if none)Any single success is enough.

🎮 Play the Pixel‑Art Game!

If you enjoyed this story, check out the pixel‑art game I built to go with it. Click the screenshot below, pick your Promise method, and try to survive the night!

Feedback welcome!
If you spot any mistakes or have suggestions, let me know. You can find me on LinkedIn and X where I share more fun code snippets.

0 views
Back to Blog

Related posts

Read more »

Array Methods You Must Know

Mutating Methods Change Original Array - push – Add to end - pop – Remove from end - shift – Remove from start - unshift – Add to start All of these do not ret...