try...catch 에러 핸들링

2023. 12. 22. 14:47Study/JavaScript

보통의 스크립트에서 에러가 발생하면 스크립트가 즉시 중단되고, 콘솔에 에러가 출력됩니다.

그러나 try...catch문을 사용하면 스크립트가 죽는 걸 방지하고, 에러를 잡아서(catch) 더 합당한 무언가를 할 수 있게 됩니다.

 

try...catch

try {
	// code
	throw new Error('에러 발생');
} catch (e) {
	// error handling
} finally {
	// code
}

 

 

try...catch의 알고리즘

1. 먼저, try{...} 안의 코드가 실행됩니다.

2. 에러가 없다면 try 안의 마지막 줄까지 실행되고, catch 블록은 건너뜁니다.

3. 에러가 있다면 try 안 코드의 실행이 중단되고, catch(e) 블록으로 제어 흐름이 넘어갑니다. 변수 e는 무슨 일이 일어났는지에 대한 설명이 담긴 객체를 포함합니다.

4. 에러 여부와 관계 없이, finally 안의 코드가 실행됩니다.

 

이렇게 try{...} 블록 안에서 에러가 발생해도 catch 에서 에러를 처리하기 때문에 스크립트가 중단되지 않습니다.

 

 

try...catch는 오직 런타임 에러에만 동작합니다.

try...catch는 실행 가능한 (runnable) 코드에만 동작합니다. 실행 가능한 코드는 유효한 JavaScript 코드를 의미합니다.

중괄호 짝이 안 맞는 것처럼 코드가 문법적으로 잘못된 경우에는 try...catch가 동작하지 않습니다.

  • parse-time 에러 : 코드를 읽는 도중에 발생하는 에러, 엔진은 이 코드를 이해할 수 없기 때문에 parse-time 에러는 코드 안에서 복구가 블가능합니다.
  • runtime error (런타임 에러) or Exception (예외) : 유효한 코드 안에서 발생한 에러. try...catch 문은 런타임 에러에만 동작합니다.

 

try...catch는 동기적으로 동작합니다.

setTimeout 처럼 '스케줄 된(scheduled)' 코드에서 발생한 예외는 try...catch 에서 잡아낼 수 없습니다.

setTimeout에 넘겨진 익명 함수는 엔진이 try...catch를 떠난 다음에서야 실행되기 때문입니다.

스케줄 된 내부의 예외를 잡으려면 반드시 try...catch문 내부에 구현해야 합니다.

// Bad Case
try {
    setTimeout(function(){
    	noSuchVariable;	// 스크립트는 여기서 죽습니다.
    }, 1000);
} catch (e) {
	console.log('작동 멈춤');
}


// Good Case
setTimeout(function(){
    try {
    	noSuchVariable; // catch 문으로 갑니다!
    } catch (e) {
    	console.log('작동 멈춤');
    }
}, 1000);

 

 

에러 객체

에러가 발생하면 자바스크립트는 에러 상세 내용이 담긴 객체를 생성합니다. 그 후 catch 블록에 이 객체를 인수로 전달합니다.

try {
	// code
} catch (e) {	// e : 에러 객체
	// ...
}

 

내장 에러 전체와 객체는 두 가지 주요 프로퍼티를 가집니다.

name

  • 에러 이름, 정의 되지 않은 변수 때문에 발생한 에러라면 "ReferenceError"가 이름이 됩니다. (ReferenceError)

message

  • 에러 상세 내용을 담고 있는 문자 메시지
  • 표준은 아니지만, name과 message 이외의 대부분의 호스트 환경에서 지원하는 프로퍼티도 있습니다.
    stack은 가장 널리 사용되는 비표준 프로퍼티 중 하나입니다.
    (aa is not defined)

stack

  • 현재 호출 스택, 에러를 유발한 중첩 호출들의 순서 정보를 가진 문자열로 디버깅 목적으로 사용됩니다.
    (ReferenceError: aa is not defined at...)

 

 

선택적 'catch' 바인딩

에러에 대한 자세한 정보가 필요하지 않으면, catch에서 이를 생략할 수 있습니다.

 

 

'try...catch' 사용하기

잘못된 json을 JSON.parse 할 경우 에러를 만들기 때문에 스크립트가 중단됩니다.

서버에서 전달받은 데이터가 잘못되어 스크립트가 중단될 경우, 사용자는 개발자 콘솔을 열지 않는 이상 절대 원인을 알 수 없습니다.

 

try...catch를 사용해 이를 처리해 봅시다.

let json = "{Bad JSON}"

try {
    let user = JSON.parse(json);
    console.log(user.name);
} catch (e) {
    console.log('error가 있어 재요청을 시도합니다.');
    console.log(e.name);
    console.log(e.message);
}

 

이 예시에서는 에러가 발생했다는 것만 보여주지만,

catch 블록 안에서 새로운 네트워크 요청 보내기, 사용자에게 대안 제안하기, 로깅 장치에 에러 정보 보내기 등과 같은 구체적인 일을 할 수 있습니다.

 

직접 에러를 만들어서 던지기 'throw' 연산자

throw 연산자는 에러를 생성합니다.

 

이론적으로 Object 자리에 어떤 것이든 에러 객체(error object)로 사용할 수 있습니다.

그러나 내장 에러와의 호환을 위해 여러 객체에 name과 message 프로퍼티를 넣어주는 것을 권장합니다.

 

JavaScript는 Error, SyntaxError, ReferenceError, TypeError 등의 표준 에러 객체 관련 생성자를 지원합니다.

이 생성자들로 여러 객체 에러를 만들 수도 있습니다.

let error = new Error(message);
// or
let error = new SyntaxError(message);
let error = new ReferenceError(message);
// ...

 

일반 객체가 아닌 내장 생성자를 사용해 만든 내장 에러 객체의 name 프로퍼티는 생성자 이름과 동일한 값을 갖습니다.

프로퍼티 message의 값은 인수에서 가져옵니다.

 

 

에러 다시 던지기 (rethrowing)

에러 종류와 관계 없이 동일한 방법으로 에러를 처리하는 것은 디버깅을 어렵게 만들기 때문에 좋지 않습니다.

이런 문제를 피하고자 '다시 던지기 (rethrowing)' 기술을 사용합니다.

  • catch가 모든 에러를 받습니다.
  • catch (e) {...} 블록 안에서 에러 객체 e를 분석합니다.
  • 에러 처리 방법을 알지 못하면 throw e를 합니다.

보통 에러 타입을 instanceof 명령어로 체크합니다.

에러를 던지는 목표는 에러를 막는 것이 아니라 에러가 발생하면 더욱 편하게 디버깅 하는 데 있습니다.

 

 

'Study > JavaScript' 카테고리의 다른 글

getter & setter  (0) 2023.12.22
ES6 class  (1) 2023.12.22
Javascript 네이밍(Naming)과 클린 코드(Clean Code)  (0) 2023.12.22
Spread Operator  (0) 2023.12.22
정규식, 정규 표현식 regExp  (0) 2023.05.31