DEV Community

Cover image for A Horror Story About JavaScript Promise
SATYA SOOTAR
SATYA SOOTAR

Posted on

A Horror Story About JavaScript Promise

Before we dive into our midnight adventure, let's quickly understand what Promises are in JavaScript. Don't worry - it's easier than facing a monster under the bed!

What is a Promise?

A Promise is an object that represents the eventual completion (or failure) of an asynchronous operation. Think of it like a real-life promise: your friend promises to bring you coffee. Right now, you don't have the coffee - the promise is pending. Later, either you get the coffee (fulfilled) or your friend calls to say they spilled it (rejected).

In JavaScript, a Promise is created using the new Promise() constructor, which takes a function with two parameters: resolve and reject. You call resolve(value) when the operation succeeds, and reject(error) when it fails.

const coffeePromise = new Promise((resolve, reject) => {
    // Simulate making coffee
    const success = true;
    if (success) {
        resolve("β˜• Here's your coffee!");
    } else {
        reject("πŸ’” Spilled the coffee...");
    }
});
Enter fullscreen mode Exit fullscreen mode

Then and Catch

Once you have a Promise, you can attach .then() and .catch() methods to handle the result.

  • .then() runs when the Promise is fulfilled (resolved). It receives the resolved value.
  • .catch() runs when the Promise is rejected. It receives the error.
coffeePromise
    .then((message) => {
        console.log(message); // "β˜• Here's your coffee!"
    })
    .catch((error) => {
        console.log(error);   // "πŸ’” Spilled the coffee..."
    });
Enter fullscreen mode Exit fullscreen mode

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

Now that you know the basics, let's see how Promises can help you survive a terrifying 3:34 AM bathroom trip - with a little help from Promise.all, Promise.allSettled, Promise.race, and Promise.any.


It's 3:34 AM.

You wake up suddenly, and your bladder is screaming at you like a DDOS attack. You need to go to the bathroom. But there is a problem.

You are living alone in the house and have heard the stories from your grandmother that after 3 AM Ghosts lurk around the house. The monsters under the bed are most active. And your Hallway becomes a road to hell.

You lie frozen and starts to think about your options. Either wet the bed or face the darkness (Supernatural being).

Terror in the quite night

This, my friends, is exactly like handling multiple promises in JavaScript.

Let me explain -

Before you get out of the bed you need three things to happen:

  • You flip the switch of the hallway and hope it works.
  • You flip the bathroom light and hope it works.
  • You check under the bed and hope there is no Monster looking back at you while salivating πŸ‘Ή.

Lets code the Conditions :

Condition 1

const hallwayLight = new Promise((resolve, reject) => {
    // You flip the switch (You are an developer bruh! You can do anything from bed)
    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);
});
Enter fullscreen mode Exit fullscreen mode

Condition 2

const bathroomLight = new Promise((resolve, reject) => {
    // You flip the bathroom switch from bed (You have a Smart bulb!!!)
    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);
});
Enter fullscreen mode Exit fullscreen mode

Condition 3

const underBedCheck = new Promise((resolve, reject) => {
    // You shine your phone flashlight under the bed
    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);
});
Enter fullscreen mode Exit fullscreen mode

Haunted house at night

Now, depending on your personality type (and your level of desperation), you'll handle these promises differently.

1. Promise.all()

You ask yourself: "I will ONLY get out of bed if ALL THREE things happen. The hallway light MUST turn on. The bathroom light MUST turn on. And there MUST be no monster under the bed. If ANY of these fail, I'm staying right here."

Is the hallway light bulb dead? Well, I'm peeing in bed tonight.

The bathroom light works. No monster under the bed. But who cares? The hallway light failed. The contract is broken. The deal is off. You lie there, defeated, as warm surrender spreads beneath you.

Situation:

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.
    });
Enter fullscreen mode Exit fullscreen mode

Outcome:

On success -

πŸŽ‰ All systems go! Time to sprint!
['πŸ’‘ Hallway light is ON', '🚽 Bathroom light is ON', 'πŸ›οΈ Under the bed is CLEAR']
Enter fullscreen mode Exit fullscreen mode

On Failure -

😭 NOPE. Staying in bed.
Reason: πŸ’€ Hallway light bulb is dead
Enter fullscreen mode Exit fullscreen mode

Late-night reflection in a dim room

When to use Promise.all()

  • When you need all API calls to succeed before rendering a page.
  • When you're uploading multiple files and need all to complete.

2. Promise.allSettled()

You are more practical. You decide: "Let me check EVERYTHING first. I'll wait until I know the status of all three safety measures. Then I'll make a decision based on reality."

You check:

  • Hallway light? Dead. (Rejected)
  • Bathroom light? Works! (Fulfilled)
  • Under the bed? Clear! (Fulfilled)

Okay, so you have partial information. The hallway is dark, but you have your phone. You can see the bathroom light at the end. No monsters. You make a run for it, using your phone as a flashlight.

Situation:

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);
            }
        });

        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.");
        }
    });
Enter fullscreen mode Exit fullscreen mode

Late-night dash to the bathroom

Outcome

πŸ“‹ 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
πŸƒ Good enough! Making a run for it!
Enter fullscreen mode Exit fullscreen mode

When to use Promise.allSettled()

  • When you need to know the outcome of all operations regardless of failures.
  • When uploading multiple files and you want to know which succeeded/failed.
  • When you're running a batch process and need a complete report.

3. Promise.race()

Your bladder is at critical mass. You can't wait for all checks. You can't even wait for the first successful check. You just need the FIRST thing to happen, ANYTHING, so you can react.

You swing your legs out of bed. That's the first action. You're committed now. You hear a creak? Too bad. You're running. The first event triggered your sprint, and there's no stopping.

This is reckless. This is how horror movies start. But you gotta go.

Situation

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.
    });
Enter fullscreen mode Exit fullscreen mode

Nightmare from beneath the bed

Outcome

On success -

🏁 First thing happened: πŸ’‘ Hallway light is ON
πŸš€ Taking that as a sign! Running NOW!
Enter fullscreen mode Exit fullscreen mode

On failure -

🏁 First thing happened (and it was bad): πŸ‘Ή MONSTER under the bed!
😰 Oh no. That's a bad sign. But I'm already out of bed!
*Screaming intensifies*
Enter fullscreen mode Exit fullscreen mode

When to use Promise.race()

  • When implementing timeouts (Promise.race([actualRequest, timeoutPromise])).
  • When you need the fastest response from multiple sources.

4. Promise.any()

You're smart. You need one successful safety measure. Just one. You try the hallway light:

Click. Nothing. Darkness. (Rejection)

Okay, scary, but you're not giving up. You try the bathroom light:

Click. LIGHT! (Fulfilled)

YES! You can see the bathroom door! You don't care about the monster under the bed anymore. You have light. You run.

If ALL three fail? No lights, monster under bed? Then you're truly doomed. You stay in bed and accept your fate.

Situation:

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.");
    });
Enter fullscreen mode Exit fullscreen mode

Man lighting up a dark hallway

Outcome

On Success -

🎯 Found one working safety measure: 🚽 Bathroom light is ON
πŸƒ That's enough! Making my move!
Enter fullscreen mode Exit fullscreen mode

On failure -

πŸ’€ ALL safety measures failed!
Errors: ['πŸ’€ Hallway light bulb is dead', 'πŸ‘» Bathroom light is dead', 'πŸ‘Ή MONSTER under the bed!']
Staying in bed forever.
Enter fullscreen mode Exit fullscreen mode

When to use Promise.any()

  • When you need any successful response from multiple sources.
  • When implementing fallback APIs (try server A, if it fails, try server B).

The Moral of the Story

  1. If you're a control freak, use Promise.all() and accept that you'll sometimes wet the bed.
  2. If you're a data analyst, use Promise.allSettled() and make informed decisions.
  3. If you're desperate, use Promise.race() and hope for the best (but probably scream a lot).
  4. If you're smart, use Promise.any() and take the first win you can get.

Victory in the calm morning light

And remember: Always check for monsters before getting out of bed at 3 AM. Or use Promise.any() and just need one light to work.


πŸ•ΉοΈ Play the Game

If you enjoyed this story, you'll love the pixel-art game I built to go with it. Click the screenshot below, choose your Promise method, and survive the night!

Play the 3 AM Bathroom Game


Hope you liked this Story. If there's any mistake or something I can improve, do tell me. You can find me on LinkedIn and X, I post more stuff there.

Top comments (2)

Collapse
 
6116hayat profile image
Umar Hayat

I liked the read, the game at the is awesome too

Collapse
 
harman_panwar_46de8d9454b profile image
Harman Panwar

No way bro even cooked up a game