Node.js비동기와 런타임

async error와 unhandled rejection

callback, Promise, async function에서 에러가 어떻게 전파되는지와 unhandled rejection을 어떤 관점으로 봐야 하는지 정리합니다.

마지막 수정 2026년 3월 22일

기본 패턴

javascript
try {
  await doWork();
} catch (error) {
  console.error("request failed", error);
}

설명

  • Node.js에서 에러는 모두 같은 방식으로 흐르지 않습니다. callback 스타일, Promise 체인, async/await, EventEmitter는 각각 실패를 드러내는 방식이 다릅니다.
  • callback 시대에는 보통 첫 번째 인자로 err를 넘겼고, Promise 시대에는 reject를 통해 실패를 표현합니다. async function은 문법이 단순해 보이지만, 결국 reject를 throw처럼 다루게 해 주는 문법적 래퍼라고 볼 수 있습니다.
  • 중요한 것은 "비동기 경계마다 누가 실패를 소비하는가"입니다. await 주변에 try/catch가 없거나, Promise에 .catch()가 없으면 unhandled rejection이 생길 수 있습니다.
  • unhandled rejection은 단순 경고가 아니라, 프로그램이 어디선가 실패를 의도적으로 다루지 않았다는 신호입니다. 서비스 코드에서는 로깅, 요청 컨텍스트 정리, 종료 정책까지 함께 생각해야 합니다.
  • 실무 감각으로 보면 에러 모델은 문법보다 책임 분배의 문제입니다. 어디서 잡고, 어디까지 전파하고, 어떤 수준에서 프로세스를 종료할지를 미리 정해 두는 편이 좋습니다.

빠른 정리

모델실패 표현 방식
callback첫 번째 err 인자
Promisereject
async/awaittry/catch로 읽는 Promise reject
EventEmittererror 이벤트
핵심 질문이 실패를 누가 소비하는가

주의할 점

try/catch가 있다고 해서 모든 비동기 실패를 자동으로 잡는 것은 아닙니다. await하지 않은 Promise나 별도 이벤트 흐름은 그 바깥에서 실패할 수 있으므로, 비동기 경계를 어디까지 묶고 있는지 함께 봐야 합니다.

참고 링크

2 sources