November 16, 2021
프라미스가 거부되면 제어 흐름이 제일 가까운 rejection 핸들러로 넘어가기 때문에 프라미스 체인을 사용하면 에러를 쉽게 처리할 수 있습니다. 이는 실무에서 아주 유용한 기능입니다.
존재하지 않는 주소를 fetch
에 넘겨주는 예시를 살펴봅시다. .catch
에서 에러를 처리합니다.
*fetch('<https://no-such-server.blabla>') // 거부*.then(response => response.json())
.catch(err => alert(err)) // TypeError: failed to fetch (출력되는 내용은 다를 수 있음)
예시에서 보듯 .catch
는 첫번째 핸들러일 필요가 없고 하나 혹은 여러 개의 .then
뒤에 올 수 있습니다.
이번엔 사이트에는 아무런 문제가 없지만 응답으로 받은 JSON의 형식이 잘못된 경우를 살펴봅시다. 가장 쉬운 에러 처리 방법은 체인 끝에 .catch
를 붙이는 것입니다.
체인 마지막의 .catch
는 try..catch
와 유사한 역할을 합니다. .then
핸들러를 원하는 만큼 사용하다 마지막에 .catch
하나만 붙이면 .then
핸들러에서 발생한 모든 에러를 처리할 수 있습니다.
일반 try..catch
에선 에러를 분석하고, 처리할 수 없는 에러라 판단되면 에러를 다시 던질 때가 있습니다. 프라미스에도 유사한 일을 할 수 있습니다.
.catch
안에서 throw
를 사용하면 제어 흐름이 가장 가까운 곳에 있는 에러 핸들러로 넘어갑니다. 여기서 에러가 성공적으로 처리되면 가장 가까운 곳에 있는 .then
핸들러로 제어 흐름이 넘어가 실행이 이어집니다.
아래 예시의 .catch
는 에러를 성공적으로 처리합니다.
// 실행 순서: catch -> catch
new Promise((resolve, reject) => {
throw new Error("에러 발생!");
}).catch(function(error) { // (*)
if (error instanceof URIError) {
// 에러 처리
} else {
alert("처리할 수 없는 에러");
*throw error; // 에러 다시 던지기*}
}).then(function() {
/* 여기는 실행되지 않습니다. */
}).catch(error => { // (**)
alert(`알 수 없는 에러가 발생함: ${error}`);
// 반환값이 없음 => 실행이 계속됨
});
실행 흐름이 첫 번째 .catch
(*)
로 넘어갔다가 다음 .catch
(**)
로 이어지는 것을 확인할 수 있습니다.
.catch
는 프라미스에서 발생한 모든 에러를 다룹니다. reject()
가 호출되거나 에러가 던져지면 .catch
에서 이를 처리합니다..catch
는 에러를 처리하고 싶은 지점에 정확히 위치시켜야 합니다. 물론 어떻게 에러를 처리할지 알고 있어야 하죠. 핸들러에선 에러를 분석하고(커스텀 에러 클래스가 이때 도움이 됩니다) 알 수 없는 에러(프로그래밍 실수로 발생한 에러일 확률이 높습니다)는 다시 던질 수 있습니다..catch
를 사용하지 않아도 괜찮습니다.unhandledrejection
이벤트 핸들러를 사용해 처리되지 않은 에러를 추적하고, 이를 사용자(혹은 서버에)에게 알려서 애플리케이션이 아무런 설명도 없이 ‘그냥 죽는걸’ 방지합시다. 브라우저 환경에선 예방에 unhandledrejection
을, 다른 환경에선 유사한 핸들러를 사용할 수 있습니다.