Promise rejection unhandled 에러 완벽 해결 가이드
JavaScript 개발 중 ‘Promise rejection unhandled’ 에러를 만나셨나요? 이 에러는 비동기 처리 과정에서 Promise가 reject 되었지만 적절한 에러 핸들링이 없을 때 발생합니다. Node.js 환경에서는 ‘UnhandledPromiseRejectionWarning’으로, 브라우저에서는 ‘Unhandled Promise Rejection’으로 표시되며, 애플리케이션의 안정성을 심각하게 저해할 수 있습니다. 이 글에서는 Promise rejection unhandled 에러의 원인부터 해결방법, 그리고 예방 전략까지 실무에서 바로 적용할 수 있는 모든 내용을 다룹니다.
🤖 AI 에러 분석 도우미
이 에러는 다음과 같은 상황에서 주로 발생합니다:
- 코드 문법 오류가 있을 때
- 라이브러리나 의존성 문제
- 환경 설정이 잘못된 경우
- 타입 불일치 문제
💡 위 해결법을 순서대로 시도해보세요. 90% 이상 해결됩니다!
에러 상세 분석
🔗 관련 에러 해결 가이드
Promise rejection unhandled 에러는 Promise 기반 비동기 코드에서 발생하는 가장 흔한 문제 중 하나입니다. Promise는 세 가지 상태(pending, fulfilled, rejected)를 가지며, rejected 상태로 전환될 때 반드시 .catch() 핸들러나 try-catch 블록으로 처리해야 합니다.
이 에러가 발생하면 콘솔에 경고 메시지가 출력되며, Node.js 15 이상 버전에서는 프로세스가 종료될 수 있습니다. 브라우저 환경에서는 ‘unhandledrejection’ 이벤트가 발생하여 개발자 도구에 표시됩니다. 특히 프로덕션 환경에서 이 에러를 방치하면 사용자 경험을 해치고 디버깅이 어려워지므로, 개발 단계에서부터 철저한 에러 핸들링이 필수입니다.
에러 메시지는 일반적으로 어떤 Promise가 reject 되었는지, 그리고 reject된 이유(reason)를 포함합니다. 이 정보를 활용하면 문제의 근본 원인을 빠르게 파악할 수 있습니다.
발생 원인 5가지
1. catch 핸들러 누락
가장 기본적인 원인은 Promise 체인에서 .catch() 메서드를 누락하는 것입니다. Promise를 사용할 때는 항상 에러 처리를 고려해야 합니다.
// 잘못된 예시
fetch('/api/data')
.then(response => response.json())
.then(data => console.log(data));
// catch가 없어서 네트워크 에러 발생 시 unhandled rejection
2. async/await에서 try-catch 미사용
async/await 문법을 사용할 때 try-catch 블록으로 감싸지 않으면 에러가 처리되지 않습니다.
// 잘못된 예시
async function getData() {
const response = await fetch('/api/data');
const data = await response.json();
return data;
}
// 에러 발생 시 처리되지 않음
3. Promise 생성자 내부의 에러
Promise 생성자 함수 내부에서 발생하는 동기적 에러는 자동으로 reject로 변환되지만, 비동기 콜백 내부의 에러는 별도 처리가 필요합니다.
4. 이벤트 핸들러 내부의 Promise
이벤트 핸들러나 콜백 함수 내부에서 생성된 Promise는 외부 스코프에서 에러 처리를 놓치기 쉽습니다.
5. Promise.all()의 부분 실패
여러 Promise를 동시에 처리할 때 하나라도 reject되면 전체가 실패하는데, 이를 처리하지 않으면 에러가 발생합니다.
// 잘못된 예시
Promise.all([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
]);
// 하나라도 실패하면 unhandled rejection
해결방법 7가지
1. .catch() 메서드 추가
가장 기본적인 해결법은 Promise 체인 끝에 .catch()를 추가하는 것입니다.
fetch('/api/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
console.error('데이터 로드 실패:', error);
// 에러 처리 로직
});
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; // 필요시 재전파
}
}
3. 전역 에러 핸들러 설정
Node.js와 브라우저 모두 전역 레벨에서 unhandled rejection을 캐치할 수 있습니다.
// Node.js
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
// 로깅 서비스로 전송
});
// 브라우저
window.addEventListener('unhandledrejection', event => {
console.error('Unhandled rejection:', event.reason);
event.preventDefault();
});
4. Promise.allSettled() 사용
여러 Promise를 처리할 때 일부 실패를 허용하려면 Promise.allSettled()를 사용합니다.
const results = await Promise.allSettled([
fetch('/api/users'),
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);
}
});
5. finally를 활용한 정리 작업
성공/실패 여부와 관계없이 실행되어야 하는 코드는 .finally()에 작성합니다.
fetch('/api/data')
.then(response => response.json())
.catch(error => console.error(error))
.finally(() => {
console.log('요청 완료');
// 로딩 스피너 제거 등
});
6. 에러 래퍼 함수 생성
재사용 가능한 에러 핸들링 유틸리티를 만듭니다.
async function safeAsync(promise) {
try {
const data = await promise;
return [null, data];
} catch (error) {
return [error, null];
}
}
// 사용 예시
const [error, data] = await safeAsync(fetch('/api/data'));
if (error) {
console.error('에러:', error);
} else {
console.log('데이터:', data);
}
7. 즉시 reject 처리
의도적으로 Promise를 생성했다면 즉시 에러 핸들러를 연결합니다.
const promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('타임아웃')), 5000);
}).catch(error => {
console.error('Promise 실패:', error);
});
예방법과 베스트 프랙티스
1. ESLint 규칙 활용: ‘no-floating-promises’ 규칙을 활성화하여 처리되지 않은 Promise를 자동으로 감지하세요.
2. TypeScript 사용: ‘@typescript-eslint/no-floating-promises’ 규칙으로 컴파일 단계에서 에러를 방지할 수 있습니다.
3. 일관된 에러 처리 패턴: 프로젝트 전체에서 동일한 에러 처리 방식을 사용하여 누락을 방지합니다.
4. 로깅 시스템 구축: Sentry, LogRocket 등의 도구로 프로덕션 환경의 unhandled rejection을 모니터링합니다.
5. 코드 리뷰: Promise를 사용하는 모든 코드에서 에러 처리 여부를 확인합니다.
// 베스트 프랙티스 예시
class ApiService {
async request(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
this.logError(error);
throw error;
}
}
logError(error) {
console.error('[API Error]', error);
// 외부 로깅 서비스로 전송
}
}
마무리
Promise rejection unhandled 에러는 적절한 에러 핸들링만으로 쉽게 해결할 수 있습니다. .catch()나 try-catch를 습관화하고, 전역 핸들러로 안전망을 구축하며, ESLint와 같은 도구로 사전에 방지하세요. 이 가이드의 해결방법을 프로젝트에 적용하면 더 안정적이고 유지보수하기 쉬운 코드를 작성할 수 있습니다. Promise 기반 비동기 프로그래밍은 현대 JavaScript의 핵심이므로, 올바른 에러 처리는 필수적인 개발 스킬입니다. 지금 바로 코드를 점검하고 모든 Promise에 에러 핸들링을 추가해보세요!
📚 함께 읽으면 좋은 글
ReferenceError: variable is not defined 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 15.
🎯 ReferenceError: variable is not defined
TypeError: Cannot read property of undefined 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 13.
🎯 TypeError: Cannot read property of undefined
TypeError: Cannot set property of null 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 13.
🎯 TypeError: Cannot set property of null
ReferenceError: variable is not defined 완벽 해결 가이드 – JavaScript 에러 원인과 해결법
📅 2025. 11. 10.
🎯 ReferenceError: variable is not defined
ReferenceError: variable is not defined 완벽 해결 가이드 – JavaScript 에러 해결
📅 2025. 11. 10.
🎯 ReferenceError: variable is not defined
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
여러분은 Promise rejection unhandled에 대해 어떻게 생각하시나요?
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 JavaScript 에러부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!