본문 바로가기
기술의기록

JavaScript Promise, 이제 제대로 알아보자!

by Jeremy Winchester 2025. 8. 7.
반응형

안녕하세요, 여러분! 오늘은 JavaScript 개발을 하면서 정말 많이 만나게 되는 Promise에 대해 이야기해보려고 해요. 혹시 콜백 지옥에 빠져본 적 있으신가요? 아니면 비동기 처리 때문에 머리가 아팠던 경험이 있으신가요? 그렸다면 오늘 글이 여러분에게 정말 도움이 될 거예요! 😊

Promise는 처음엔 어려워 보이지만, 한 번 제대로 이해하고 나면 정말 강력한 도구가 되거든요. 차근차근 함께 알아볼까요?

🤔 Promise가 뭐길래?

Promise는 말 그대로 "약속"이에요. JavaScript에서 비동기 작업의 결과를 나타내는 객체인데요, 간단히 말하면 "지금은 값이 없지만, 나중에 값을 줄게!"라는 약속을 하는 거죠.

예를 들어, 친구에게 "내일 카페에서 만나자"고 약속했다고 생각해보세요. 이 약속은 세 가지 상태를 가질 수 있어요:

  • 대기 중(Pending): 아직 내일이 오지 않음
  • 이행됨(Fulfilled): 약속대로 카페에서 만남
  • 거부됨(Rejected): 급한 일이 생겨서 못 만남

Promise도 정확히 이런 식으로 동작해요!

📝 Promise 기본 문법 살펴보기

Promise 생성하기

 
 
javascript
const myPromise = new Promise((resolve, reject) => {
  // 비동기 작업 수행
  const success = true; // 예시
  
  if (success) {
    resolve("작업 성공!"); // 성공했을 때
  } else {
    reject("작업 실패!"); // 실패했을 때
  }
});

Promise 사용하기

 
 
javascript
myPromise
  .then(result => {
    console.log(result); // "작업 성공!" 출력
  })
  .catch(error => {
    console.log(error); // 에러 발생 시 실행
  })
  .finally(() => {
    console.log("작업 완료!"); // 성공/실패와 관계없이 실행
  });

🎯 실전에서 Promise 활용하기

1. API 호출할 때

 
 
javascript
function fetchUserData(userId) {
  return new Promise((resolve, reject) => {
    fetch(`/api/users/${userId}`)
      .then(response => {
        if (response.ok) {
          return response.json();
        } else {
          throw new Error('사용자 정보를 불러올 수 없습니다');
        }
      })
      .then(data => resolve(data))
      .catch(error => reject(error));
  });
}

// 사용 예시
fetchUserData(123)
  .then(user => {
    console.log('사용자 정보:', user);
  })
  .catch(error => {
    console.error('에러 발생:', error);
  });

2. 타이머 함수 만들기

 
 
javascript
function delay(ms) {
  return new Promise(resolve => {
    setTimeout(resolve, ms);
  });
}

// 3초 후에 메시지 출력
delay(3000)
  .then(() => {
    console.log('3초가 지났습니다!');
  });

🔥 Promise의 강력한 메서드들

Promise.all() - 모든 약속이 지켜질 때까지

여러 개의 Promise를 동시에 실행하고, 모든 것이 완료될 때까지 기다려요.

 
 
javascript
const promise1 = fetch('/api/data1');
const promise2 = fetch('/api/data2');
const promise3 = fetch('/api/data3');

Promise.all([promise1, promise2, promise3])
  .then(responses => {
    console.log('모든 데이터를 받았어요!', responses);
  })
  .catch(error => {
    console.log('하나라도 실패하면 여기로 와요', error);
  });

Promise.race() - 가장 빠른 놈이 승자

 
 
javascript
const slowPromise = delay(3000).then(() => '느린 작업');
const fastPromise = delay(1000).then(() => '빠른 작업');

Promise.race([slowPromise, fastPromise])
  .then(result => {
    console.log(result); // "빠른 작업" 출력
  });

Promise.allSettled() - 결과를 모두 확인하고 싶을 때

 
 
javascript
const promises = [
  Promise.resolve('성공1'),
  Promise.reject('실패1'),
  Promise.resolve('성공2')
];

Promise.allSettled(promises)
  .then(results => {
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        console.log(`${index}: 성공 - ${result.value}`);
      } else {
        console.log(`${index}: 실패 - ${result.reason}`);
      }
    });
  });

💡 Promise 사용 시 주의사항

1. 체이닝할 때 return 잊지 말기

 
 
javascript
// ❌ 잘못된 예시
myPromise
  .then(result => {
    fetch('/api/data'); // return을 빼먹음!
  })
  .then(data => {
    console.log(data); // undefined 출력됨
  });

// ✅ 올바른 예시
myPromise
  .then(result => {
    return fetch('/api/data'); // return을 꼭 써주기!
  })
  .then(response => response.json())
  .then(data => {
    console.log(data); // 제대로 된 데이터 출력
  });

2. 에러 처리는 필수!

 
 
javascript
// ✅ 에러 처리가 있는 좋은 예시
fetchData()
  .then(data => {
    return processData(data);
  })
  .then(processedData => {
    console.log(processedData);
  })
  .catch(error => {
    console.error('어디선가 에러가 발생했어요:', error);
    // 사용자에게 친화적인 에러 메시지 표시
  });

🚀 async/await와 함께 사용하기

Promise와 async/await는 찰떡궁합이에요! 더 깔끔한 코드를 작성할 수 있거든요.

 
 
javascript
// Promise만 사용할 때
function getUserInfo(userId) {
  return fetchUser(userId)
    .then(user => {
      return fetchUserPosts(user.id);
    })
    .then(posts => {
      return fetchPostComments(posts[0].id);
    })
    .then(comments => {
      return { user, posts, comments };
    })
    .catch(error => {
      console.error(error);
    });
}

// async/await 사용할 때
async function getUserInfo(userId) {
  try {
    const user = await fetchUser(userId);
    const posts = await fetchUserPosts(user.id);
    const comments = await fetchPostComments(posts[0].id);
    
    return { user, posts, comments };
  } catch (error) {
    console.error(error);
  }
}

🎪 실무에서 자주 쓰이는 Promise 패턴

재시도 로직 구현하기

 
 
javascript
function retryPromise(promiseFunction, maxRetries = 3) {
  return new Promise((resolve, reject) => {
    let attempts = 0;
    
    function attempt() {
      attempts++;
      promiseFunction()
        .then(resolve)
        .catch(error => {
          if (attempts < maxRetries) {
            console.log(`${attempts}번째 시도 실패, 재시도합니다...`);
            setTimeout(attempt, 1000 * attempts); // 점진적 대기
          } else {
            reject(error);
          }
        });
    }
    
    attempt();
  });
}

병렬 처리로 성능 최적화

 
 
javascript
// ❌ 순차 처리 (느림)
async function getDataSequentially() {
  const data1 = await fetchData1(); // 2초
  const data2 = await fetchData2(); // 2초
  const data3 = await fetchData3(); // 2초
  // 총 6초 소요
}

// ✅ 병렬 처리 (빠름)
async function getDataInParallel() {
  const [data1, data2, data3] = await Promise.all([
    fetchData1(), // 2초
    fetchData2(), // 2초  
    fetchData3()  // 2초
  ]);
  // 총 2초 소요!
}

🌈 마무리하며

Promise는 처음엔 어려워 보이지만, 한 번 익숙해지면 정말 강력한 도구가 되어줘요. 비동기 처리의 복잡함을 깔끔하게 정리해주고, 코드의 가독성도 크게 향상시켜주거든요.

오늘 배운 내용을 정리해보면:

  • Promise는 비동기 작업의 약속을 나타내는 객체
  • then, catch, finally로 결과를 처리
  • Promise.all, race, allSettled 등의 유용한 메서드들
  • async/await와 함께 사용하면 더욱 깔끔한 코드 작성 가능

여러분도 이제 Promise와 친해져서, 더 멋진 JavaScript 코드를 작성해보세요! 혹시 궁금한 점이 있으시면 언제든 댓글로 남겨주세요. 함께 성장하는 개발자가 되어요! 💪

반응형