🛠️ Promise rejection unhandled 완벽 해결법 – 원인부터 예방까지

개발 에러 해결 가이드 - FixLog 노트

Promise rejection unhandled 완벽 해결법 – 원인부터 예방까지

1. Promise rejection unhandled 에러란?

JavaScript 개발 중 갑자기 콘솔에 ‘Promise rejection unhandled’ 에러가 나타나 당황한 경험이 있으신가요? 이 에러는 Promise가 reject되었지만 이를 처리하는 코드가 없을 때 발생하는 매우 흔한 에러입니다. 특히 비동기 작업이 많은 현대 웹 애플리케이션에서 자주 마주치게 되는데, 방치할 경우 애플리케이션이 예기치 않게 종료되거나 버그를 유발할 수 있습니다. 이 글에서는 Promise rejection unhandled 에러의 원인을 깊이 분석하고, 실전에서 바로 적용 가능한 7가지 해결 방법과 예방법까지 완벽하게 정리했습니다. 지금부터 이 성가신 에러와 영원히 작별할 수 있는 방법을 알아보겠습니다.

🤖 AI 에러 분석 도우미

이 에러는 다음과 같은 상황에서 주로 발생합니다:

  • 코드 문법 오류가 있을 때
  • 라이브러리나 의존성 문제
  • 환경 설정이 잘못된 경우
  • 타입 불일치 문제

💡 위 해결법을 순서대로 시도해보세요. 90% 이상 해결됩니다!

2. 에러 상세 분석

Promise rejection unhandled 에러는 정확히 말하면 ‘UnhandledPromiseRejectionWarning’이라는 이름으로 Node.js 환경에서 표시되며, 브라우저에서는 ‘Unhandled Promise Rejection’으로 나타납니다. 이 에러의 핵심은 Promise 체인에서 reject된 상태를 catch하지 않았다는 것입니다.

Promise는 JavaScript의 비동기 처리를 위한 객체로, pending(대기), fulfilled(이행), rejected(거부) 세 가지 상태를 가집니다. rejected 상태가 되면 반드시 이를 처리해야 하는데, .catch() 메서드나 try-catch 블록으로 처리하지 않으면 시스템이 이를 감지하여 경고를 발생시킵니다.

Node.js 15 버전부터는 이 에러를 방치할 경우 프로세스가 강제 종료되므로 더욱 주의가 필요합니다. 브라우저 환경에서도 unhandledrejection 이벤트가 발생하며, 사용자 경험을 해칠 수 있는 심각한 문제로 이어질 수 있습니다. 따라서 모든 Promise는 반드시 에러 처리 로직을 동반해야 합니다.

3. 발생 원인 5가지

3.1 catch 블록 누락

가장 흔한 원인으로, Promise 체인에서 .catch()를 작성하지 않은 경우입니다. 개발자가 성공 케이스만 고려하고 실패 케이스를 간과할 때 자주 발생합니다.

// 잘못된 예
fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data));
// .catch()가 없어서 네트워크 에러 시 unhandled rejection 발생

3.2 async/await에서 try-catch 미사용

async/await 문법을 사용하면서 try-catch로 감싸지 않은 경우입니다. async 함수 내부의 에러는 자동으로 rejected Promise로 변환되므로 반드시 처리해야 합니다.

// 잘못된 예
async function getData() {
  const response = await fetch('/api/data');
  const data = await response.json();
  return data;
}
// try-catch가 없어 fetch 실패 시 에러 발생

3.3 중첩된 Promise에서 내부 에러 처리 누락

Promise 안에서 또 다른 Promise를 생성할 때, 내부 Promise의 에러 처리를 빠뜨리는 경우입니다.

// 잘못된 예
Promise.resolve()
  .then(() => {
    return fetch('/api/data'); // 이 Promise의 에러가 처리되지 않음
  })
  .catch(err => console.error(err));

3.4 이벤트 핸들러 내 비동기 에러

이벤트 리스너나 콜백 함수 내에서 Promise를 사용하지만 에러를 처리하지 않는 경우입니다. 이벤트 핸들러는 별도의 실행 컨텍스트에서 동작하므로 에러가 외부로 전파되지 않습니다.

// 잘못된 예
button.addEventListener('click', () => {
  fetch('/api/submit'); // 에러 처리 없음
});

3.5 Promise.all()에서 하나라도 실패

여러 Promise를 동시에 처리할 때 Promise.all()을 사용하는데, 하나라도 reject되면 전체가 reject되며, 이를 catch하지 않으면 에러가 발생합니다.

// 잘못된 예
Promise.all([
  fetch('/api/user'),
  fetch('/api/posts'),
  fetch('/api/comments')
]);
// 하나라도 실패하면 unhandled rejection

4. 해결방법 7가지

4.1 .catch() 메서드 추가

가장 기본적인 해결법으로, 모든 Promise 체인 끝에 .catch()를 추가합니다.

// 올바른 예
fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    console.error('데이터 로드 실패:', error);
    // 사용자에게 에러 메시지 표시
  });

4.2 async/await에 try-catch 적용

async 함수 내부를 try-catch로 감싸 에러를 처리합니다.

// 올바른 예
async function getData() {
  try {
    const response = await fetch('/api/data');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('에러 발생:', error);
    throw error; // 필요 시 에러 재전파
  }
}

4.3 전역 에러 핸들러 설정

모든 unhandled rejection을 잡아내는 전역 핸들러를 설정합니다.

// 브라우저 환경
window.addEventListener('unhandledrejection', event => {
  console.error('처리되지 않은 Promise 거부:', event.reason);
  event.preventDefault(); // 기본 에러 로깅 방지
});

// Node.js 환경
process.on('unhandledRejection', (reason, promise) => {
  console.error('처리되지 않은 거부:', reason);
  // 로깅 시스템에 기록
});

4.4 Promise.allSettled() 사용

Promise.all() 대신 Promise.allSettled()를 사용하면 일부 실패해도 모든 결과를 받을 수 있습니다.

// 올바른 예
const results = await Promise.allSettled([
  fetch('/api/user'),
  fetch('/api/posts'),
  fetch('/api/comments')
]);

results.forEach((result, index) => {
  if (result.status === 'fulfilled') {
    console.log(`요청 ${index} 성공:`, result.value);
  } else {
    console.error(`요청 ${index} 실패:`, result.reason);
  }
});

4.5 finally 블록 활용

성공/실패 여부와 관계없이 실행되어야 하는 코드는 finally에 작성합니다.

// 올바른 예
fetch('/api/data')
  .then(response => response.json())
  .then(data => processData(data))
  .catch(error => handleError(error))
  .finally(() => {
    hideLoadingSpinner(); // 항상 실행
  });

4.6 에러 처리 래퍼 함수 생성

재사용 가능한 에러 처리 로직을 래퍼 함수로 만듭니다.

// 올바른 예
function safeAsync(fn) {
  return async function(...args) {
    try {
      return await fn(...args);
    } catch (error) {
      console.error('에러 발생:', error);
      // 에러 추적 시스템에 전송
      return null;
    }
  };
}

const safeGetData = safeAsync(async (id) => {
  const response = await fetch(`/api/data/${id}`);
  return response.json();
});

4.7 void 연산자 사용 (의도적 무시)

에러를 의도적으로 무시해야 하는 경우 void 연산자를 사용합니다.

// 올바른 예 (로깅만 하고 에러는 무시)
void fetch('/api/log').catch(err => {
  // 로깅 실패는 애플리케이션에 영향 없음
});

5. 예방법과 베스트 프랙티스

5.1 항상 에러 처리 먼저 작성

Promise를 작성할 때 성공 케이스보다 에러 처리를 먼저 고려하는 습관을 들이세요. .catch()나 try-catch를 기본 템플릿처럼 사용하면 실수를 줄일 수 있습니다.

5.2 ESLint 규칙 활용

eslint-plugin-promise 플러그인의 ‘no-floating-promises’ 규칙을 활성화하면 처리되지 않은 Promise를 자동으로 감지할 수 있습니다.

// .eslintrc.js
module.exports = {
  plugins: ['promise'],
  rules: {
    'promise/catch-or-return': 'error',
    'no-floating-promises': 'error'
  }
};

5.3 TypeScript 활용

TypeScript의 strict 모드와 함께 Promise 타입을 명시적으로 선언하면 컴파일 타임에 에러를 발견할 수 있습니다.

5.4 에러 바운더리 패턴

React 같은 프레임워크에서는 Error Boundary를 활용하여 비동기 에러도 포착하도록 설계하세요.

5.5 로깅 및 모니터링

Sentry, LogRocket 같은 에러 추적 도구를 연동하여 프로덕션 환경의 unhandled rejection을 실시간으로 모니터링하세요.

6. 마무리

Promise rejection unhandled 에러는 JavaScript 비동기 프로그래밍에서 가장 흔하게 마주치는 문제지만, 적절한 에러 처리만 구현하면 쉽게 해결할 수 있습니다. 모든 Promise에 .catch()를 추가하거나 async/await에 try-catch를 사용하는 것을 습관화하세요. 전역 에러 핸들러를 설정하고 ESLint 규칙을 활용하면 미리 예방할 수도 있습니다. 이 글에서 소개한 7가지 해결법과 베스트 프랙티스를 적용하면 더 이상 Promise rejection unhandled 에러로 고민할 필요가 없을 것입니다. 안정적인 코드로 사용자에게 더 나은 경험을 제공하세요!

📚 함께 읽으면 좋은 글

1

SyntaxError: Unexpected token 완벽 해결법 – 원인부터 예방까지

📂 JavaScript 에러
📅 2025. 10. 5.
🎯 SyntaxError: Unexpected token

2

Memory leak in JavaScript applications 완벽 해결법 – 원인부터 예방까지

📂 JavaScript 에러
📅 2025. 10. 4.
🎯 Memory leak in JavaScript applications

3

Memory leak in JavaScript applications 완벽 해결법 – 원인부터 예방까지

📂 JavaScript 에러
📅 2025. 10. 3.
🎯 Memory leak in JavaScript applications

4

SyntaxError: Unexpected token 완벽 해결법 – 원인부터 예방까지

📂 JavaScript 에러
📅 2025. 10. 3.
🎯 SyntaxError: Unexpected token

5

TypeError: Cannot set property of null 완벽 해결법 – 원인부터 예방까지

📂 JavaScript 에러
📅 2025. 10. 2.
🎯 TypeError: Cannot set property of null

💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!

📢 이 글이 도움되셨나요? 공유해주세요!

여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨


📘 페이스북


🐦 트위터


✈️ 텔레그램

🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏

💬 여러분의 소중한 의견을 들려주세요!

여러분은 Promise rejection unhandled에 대해 어떻게 생각하시나요?

💡
유용한 정보 공유

궁금한 점 질문

🤝
경험담 나누기

👍
의견 표현하기

⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨

🔔 블로그 구독하고 최신 글을 받아보세요!

📚
다양한 주제
17개 카테고리

정기 업데이트
하루 3회 발행

🎯
실용적 정보
바로 적용 가능

💡
최신 트렌드
2025년 기준

🌟 JavaScript 에러부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨

📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!

📱 전체 버전 보기