개발자
류준열
에러바운더리와 실행컨텍스트
에러바운더리는 렌더링중의 에러만 포착한다. 그 이유는 실행컨텍스트와 이벤트루프를 살펴보면 쉽게 이해할 수 있다.
에러바운더리
에러바운더리는 에러를 window 객체까지 전파시키지 않도록 중간에서 잡아주는 경계이다.
에러바운더리가 잡지 못하는 에러는 SSR, 이벤트핸들러, 비동기에서 나타는 에러이다.
근데 이걸 더 근본적으로 말하면, Call Stack에서 동기로 처리되지 않는 에러이다. (이벤트 핸들러도 Web API에서 처리)
실행컨텍스트와 함께 에러의 전파 방향 확인

위 코드의 실행컨텍스트가 Call Stack에 쌓이는 순서는 아래와 같다.

그리고 아래 내용은 Call Stack이 쌓이는 반대 방향으로 에러가 전파되는 것이다.
VM550:2 Uncaught Error: foo 에서 발생한 에러
at foo (<anonymous>:2:11)
at bar (<anonymous>:6:5)
at baz (<anonymous>:10:5)
at <anonymous>:13:1
현재 실행 중인 함수의 실행컨텍스트(foo)에서 자신을 호출한 bar로, 그 다음 호출자 baz로 마지막으로 전역코드까지 순차적으로 되돌아가며 어디서 호출되었는지 추적한다.

비동기함수는 에러 호출자가 사라진 이후에 호출된다
이때 비동기함수는 Call Stack이 비어있을때 Queue에서 호출되며 실행컨텍스트가 쌓인다.

위 그림에서는 비동기 함수 setTimeout을 호출한 bar가 종료된 이후에 setTimeout의 callback 호출된다.

즉, 비동기 함수는 실행컨텍스트 관점에서 호출관계가 끊어진다.
비동기 에러를 Error Boundary가 잡지 못하는 이유
다시 Error Boundary로 돌아와보자.
동기 코드에서는 foo → bar → baz → 전역 코드처럼 하나의 Call Stack 안에서 호출 관계가 유지된다.

따라서 foo에서 에러가 발생하면 현재 실행 컨텍스트부터 자신을 호출한 실행 컨텍스트를 따라 Call Stack을 거슬러 올라가며 에러가 전파된다.

반면 setTimeout과 같은 비동기 작업은 다르다.
const bar = () => {
setTimeout(() => {
throw new Error('에러 발생');
}, 1000);
};
bar();
setTimeout은 브라우저 타이머에서 처리되는 되어 callback을 Queue에 대기시킨다. 그리고 Call Stack에 있는 bar가 종료되었을때 새로운 실행컨텍스트로 setTimeout의 callback이 실행된다.

이 때문에 Error Boudary는 렌더링중에 발생한 에러만 캐치할 수 있다고 말하는 것이고 이는 이벤트 핸들러, 비동기 처리등 Call Stack에서 동기로 처리되지 않는 에러는 캐치 할 수 없다는 말이다.