비동기함수 Try~ catch 문

8/30/2022

작성자 : 홍원배

Try ~ catch 문의 오류처리

try ~ catch문은 블록 레벨의 스코프를 가지는 문(statement)이다
try 문 안에서 오류가 발생했을 때 catch문으로 이동하여 해당 오류를 처리한다
하지만, 비동기함수에서는 오류를 잡아주지 못한다
 
기본적으로 에러는 발생시에 함수의 호출자 방향으로 에러를 전파한다.
함수의 호출자란 자바스크립트 엔진의 콜 스택에 있는 해당 함수의 상위 함수들(콜스택 구조상으로는 하위)을 말한다. 즉, 해당 함수를 호출한 함수들이다.
함수의 호출자로 전파되는 에러가 에러를 처리해 줄 상위 호출자를 만나서 처리되어지지 못하면 프로그램은 강제종료 된다. 이게 바로 강제 종료되는 에러의 메커니즘이다.
그런데 여기서 문제는, 비동기 함수는 호출자를 찾을 수 없다는 것이다.
 
try { setTimeout(() => { throw new Error('에러를 못 잡아낸다')}, 2000) } catch(e){ console.log('에러를 해결했습니다') } // 35 // VM449:3 Uncaught Error: 에러를 못 잡아낸다 // at <anonymous>:3:15
setTimeout은 비동기함수다
 
위 코드의 예시의 setTimeout이라는 비동기 함수로 설명하자면, 실행 컨텍스트 관점 (콜 스택의 실행 참조범위)에서, setTimeout은 콜백함수로 불러줄 타이머ID를 남기고 스택에서 제거된다. 후에 스택 안에 모든 함수들이 사라졌을 때 마이크로 태스크 큐에서 실행 대기중인 타이머함수(콜백함수)가 콜 스택에 옮겨져 실행되게 되는데, 그 시점에서 에러를 처리해줄 호출자 함수는 없다.
 
 

그렇다면 비동기 함수의 오류는 어떻게 잡아줄 수 있는가?

 
Promise를 활용하면 된다
// 프로미스 객체로 감싼 비동기함수 const promise = new Promise((resolve, reject)=>{ setTimeout(()=>{ reject("reject"); }, 3000); }) // 1방법. catch로 연결해나감 promise.then(result => console.log(result)) .catch(error => console.log('에러가 해결되었습니다')); // 2방법. async await로 한번 더 처리 (async () { try { const result = await promise() // await 뒤의 올 수 있는 값은 promise }) catch (err){ console.log('에러가 해결되었습니다') })() // fetch()로 통신한 값도 promise로 감싸진 response객체이며 // response객체를 json() 해준 promise를 받아야 한다
Promise객체의 reject값은 error로 인식되어진다.
 
약속된 값인 Promise를 이용한 Promise.then이나 async await 구문은 추후에 마이크로 태스크 큐에 의해 콜백처리 되어져서 호출된다.
에러를 처리해 줄 호출자의 기능으로 Promise.catch 문이나 async에서의 try~catch문이 콜스택에 넣어져 에러를 처리해 줄 수 있는 것이다.