JavaScript Promise에 관한 공포 이야기

발행: (2026년 3월 1일 오후 08:11 GMT+9)
12 분 소요
원문: Dev.to

Source: Dev.to

위 링크에 있는 전체 글을 제공해 주시면, 해당 내용을 한국어로 번역해 드리겠습니다.
(코드 블록, URL 및 마크다운 형식은 그대로 유지됩니다.)

자정 모험 전 – 프로미스란?

“걱정 마세요 – 침대 밑 괴물을 마주하는 것보다 더 쉬워요!”

Promise는 비동기 작업의 최종 완료(또는 실패)를 나타내는 객체입니다.

실생활 비유:
친구가 커피를 가져다 주겠다고 약속합니다. 현재는 커피가 없으니 약속은 대기(pending) 상태입니다. 나중에 커피를 받으면 (fulfilled) 혹은 친구가 커피를 쏟았다고 전화하면 (rejected) 됩니다.

JavaScript에서 Promise는 new Promise() 생성자를 사용해 만들며, 두 개의 매개변수 resolvereject를 받는 함수를 전달합니다.

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

결과 처리

  • .then() 은 Promise가 fulfilled 되었을 때 실행되며, 해결된 값을 받습니다.
  • .catch() 은 Promise가 rejected 되었을 때 실행되며, 오류를 받습니다.
coffeePromise
    .then(message => {
        console.log(message); // "☕ Here's your coffee!"
    })
    .catch(error => {
        console.log(error);   // "💔 Spilled the coffee..."
    });

여러 개의 .then()을 체인으로 연결할 수 있지만, 여기서는 간단히 설명합니다.

3:34 AM 화장실 가기 – 프라미스 비유

현재 시각은 새벽 3시 34분. 방광이 DDoS 공격처럼 울부짖고 있습니다. 화장실에 가야 하지만:

  • 혼자 삽니다.
  • 할머니 이야기에 따르면 새벽 3시 이후에 귀신이 돌아다닌다고 합니다.
  • 침대 밑에 있는 괴물들이 가장 활발합니다.
  • 복도는 지옥으로 가는 길처럼 느껴집니다.

당신은 두 가지 선택지 사이에서 얼어붙었습니다:

  1. 침대에 누워서 오줌을 누기
  2. 어둠(초자연적 존재)과 맞서기

이 상황은 JavaScript에서 여러 프라미스를 다루는 것과 정확히 같습니다.

필요한 세 가지 조건

  1. 복도 조명을 켜기 – 작동하기를 바란다.
  2. 화장실 조명을 켜기 – 작동하기를 바란다.
  3. 침대 밑을 확인하기 – 괴물이 당신을 향해 침을 흘리고 있지 않기를 바란다.
// 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()

세 가지가 모두 일어나야만 침대에서 나올 거예요. 하나라도 실패하면 여기 그대로 있을 겁니다.”

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()

“먼저 모든 것을 확인해 볼게요. 세 가지 안전 조치의 상태를 모두 알 때까지 기다렸다가, 실제 상황에 따라 결정하겠습니다.”

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

📋 상황을 평가합니다:
❌ Promise 1: 💀 복도 전구가 고장났습니다
✅ Promise 2: 🚽 화장실 전등이 켜져 있습니다
✅ Promise 3: 🛏️ 침대 밑이 깨끗합니다

Promise.allSettled()를 사용해야 할 때

  • 성공이든 실패든 모든 프로미스의 결과가 필요할 때.
  • 여러 작업의 결과를 로깅하거나 보고해야 할 때.

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

“먼저 해결되는 안전 조치가 내 운명을 결정한다.”

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

Promise.race()를 사용할 때

  • 타임아웃 구현.
  • 여러 소스 중 가장 빠른 응답에 따라 동작하기.

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

any 안전 조치가 성공하는 즉시 진행할게; 하나가 성공할 때까지 실패는 무시한다.”

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

Promise.any() 사용 시점

  • 여러 중복 서비스를 시도하고, 먼저 성공하는 서비스로 진행할 때.
  • 어느 하나가 성공하면 충분한 폴백 전략을 구현할 때.

Takeaway

  • Promise.all모두 성공해야 합니다.
  • Promise.allSettled모든 프로미스의 결과를 알 수 있습니다.
  • Promise.race먼저 정착된(이행되든 거부되든) 것이 승리합니다.
  • Promise.any첫 번째 이행된 것이 승리합니다; 하나가 성공할 때까지 거부는 무시합니다.

이 도구들을 갖추면, 새벽 3시 화장실 방문이든—아니면 어떤 비동기 JavaScript 도전이든 살아남을 수 있습니다! 🚀

3시 새벽 공포 이야기를 통해 본 Promise 메서드

아래는 원본 마크다운을 정리한 버전입니다. 구조, 이모지, 서사는 그대로 유지하면서 포맷은 올바른 Markdown 규칙을 따릅니다.

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

사용 시점

  • 모든 작업이 성공해야만 다음 단계로 진행해야 할 때.
  • 예시: 여러 파일을 업로드하고 모든 업로드가 성공했을 때만 계속 진행.
  • 예시: 배치 작업이 완전히 끝난 뒤에 다음 단계로 넘어가야 할 때.

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

사용 시점

  • 성공 여부와 관계없이 모든 프라미스의 결과가 필요할 때.
  • 전형적인 시나리오:
    • 여러 파일을 업로드하고 각각이 성공했는지 실패했는지 알고 싶을 때.
    • 배치 프로세스를 실행하고 전체 보고서가 필요할 때.

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

사용 시점

  • 첫 번째 정착된 프라미스(성공 또는 실패)가 필요할 때.
  • 일반적인 사용:
    • 타임아웃 구현: Promise.race([actualRequest, timeoutPromise]).
    • 여러 소스 중 가장 빠른 응답을 얻을 때.

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

사용 시점

  • 하나의 성공적인 결과만 필요하고 나머지는 무시해도 될 때.
  • 전형적인 시나리오:
    • 대체 API(서버 A가 실패하면 서버 B 시도).
    • 단일 성공이면 진행 가능한 상황.

Quick Recap

메서드반환값선택 시점
Promise.all()모든 이행된 값들 (첫 번째 실패 시 거부)모든 것이 성공해야 할 때.
Promise.allSettled(){status, value/reason} 객체 배열, 모든 프라미스에 대해성공과 실패 모두에 대한 전체 보고서가 필요할 때.
Promise.race()첫 번째로 정착된 값 또는 거부완전성보다 속도가 중요할 때.
Promise.any()첫 번째 이행된 값 (없을 경우 AggregateError)하나의 성공만 있으면 충분할 때.

🎮 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 조회
Back to Blog

관련 글

더 보기 »

9주차: 비동기 JavaScript 이해

비동기 JavaScript 9주차는 JavaScript가 비동기 작업을 처리하는 방식을 이해하는 것이었습니다: 콜백, 프로미스, async/await, 그리고 이벤트 루프. Ca...

알아야 할 배열 메서드

변형 메서드는 원본 배열을 변경합니다 - push – 끝에 추가 - pop – 끝에서 제거 - shift – 시작에서 제거 - unshift – 시작에 추가 이 모든 메서드는 새로운 배열을 반환하지 않습니다.