[Day41] Javascript -

Validator·2023년 8월 10일
0

try, catch 구문

try, catch 에러 핸들링 구문.
보통 자바스크립트에서는 에러가 발생하면 즉시 스크립트가 중지되고, 콘솔에 에러가 출력되게 된다. 그러나 try, catch 문법을 사용하면 스크립트가 중지되는 것을 방지하고 에러를 잡아서(catch) 원하는 처리를 할 수 있게된다.

try {
	// code
} catcj (err) {
	// error handling
}

try, catch 동작 방식은 다음과 같다.

먼저 try{...} 안의 코드가 실행된다.
만약, 에러가 없다면 try 안의 마지막 줄까지 코드기 실행되고 catch 블록은 건너뛰게 된다.
에러가 있다면, try 안 코드의 실행이 중지되고 catch(err) 블록으로 제어 흐름이 넘어가게 된다. 변수 err(꼭 err라고 하지 않고 아무거나 써도 상관 없다)는 무슨 일이 일어났는지 에러에 대한 설명이 담긴 객체를 받게 된다.

위의 그림을 보면 try, catch 구문이 어떻게 작동하는지 쉽게 이해할 수 있다.
try 블록 안에서 에러가 발생하여도 cathc에서 에러를 어떻게 처리해야할지 정할 수 있기 때문에 스크립트는 죽지 않게 된다.

try {
	console.log("try start...."); // 1
    errotTest;					  // 2
    console.log("try end...."); // 실행 안 됨
} catch (err) {
	console.log(err, "error 발생!") // 3

try, catch는 오직 런타임 에러에만 동작한다.

try, catch 구문은 실행 가능한(runnable) 코드에서만 동작한다. 실행 가능한 코드란 유효한 자바스크립트 코드를 의미한다. 중괄호 짝이 안 맞는 것처럼 코드가 문법적으로 애초에 잘못된 경우에는 try, catch 구문이 작동하지 않는다.

try {
	{{{{{{{{{{
} catch (err) {
	console.log("유효하지 않은 코드이므로, 애초에 catch에서 잡히지 않는다!")'
}
// error

try, catch구문은 동기적으로 동작

setTimeout처럼 scheduled된 코드에서 발생한 에러는 try, catch에서 잡아낼 수 없다.
setTimeout에 넘겨진 익명 함수는 백그라운드로 넘어갔다가 엔진이 try, catch를 실행한 후에 이벤트 루프를 통해 콜스택으로 들어와 실행되기 때문이다.
따라서, 스케쥴 된 내부의 예외를 잡으려면 try, catch 구문을 함수 내부에 구현해야한다.

// 안 좋은 예시
try {
	setTimeout(function () {
    	noSuchVariable; // 스크립트는 여기서 죽는다.
    }, 1000);
} catch (err) {
	console.log('작동 멈춤');
}


// 좋은 예시
setTimeout(function () {
	try {
    	noSuchVariable; // 여기서 바로 catch 문으로 이동하게 된다.
    } catch (error) {
    	console.log("작동 멈춤"); // --> 이게 실행되게 된다.
    }
}, 1000);

에러 객체

에러가 발생하게 되면 자바스크립트에서 에러의 상세내용이 담긴 객체를 생성한다. 그 후 catch 블록에 이 객체를 인자로 전달하게 된다.(우리는 보통 err라고 이름 붙여서 쓴다. 다만 error이라고 쓰던 abcdef라고 쓰던 상관 없다.)

try {
	//...
} catch (err) {  // --> 에러 객체는 err에 할당되게 된다.
	// ...
}

에러 객체는 몇 가지 주요 프로퍼티를 가지게 된다.

name : 에러 이름, 정의되지 않은 변수 때문에 발생한 에러라면 "RefereenceError"라는 name을 가지게 된다.

message : 에러의 상세 내용을 담고 있는 메시지 / 표준은 아니지만 name이나 message 말고 대부분의 호스트 환경에서 지원하는 프로퍼티도 존재한다. 그 중 하나가 stack이다.

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

catch을 선택적으로 하는 방식

만약 에러에 대해서 자세한 정보가 필요하지 않다면 다음과 같은 방법으로 생략할 수도 있다.

try {
	// ...
} catch () { --> catch 인자에 아무것도 안 넣어도 됨
	// ... --> 여기서 catch에서 아무 것도 안 해줘도 된다.
}

실전에서 try, catch 사용하기

JSON으로 인코딩 된 것을 것을 parse시킬 수 있는 JSON.parse(str) 메소드가 존재한다.
이 메서드는 주로 서버 등에서 네트워크를 통해 전달받은 데이터를 디코딩하는 데 사용한다.
전달받은 데이터에 JSON.parse를 호출하는 식으로 사용된다.

let json = "{"name":"John", "age":30}"; // 서버로부터 전달받은 JSON 형식의 데이터(string 형식)

let user = JSON.parse(json); // 전달 받은 JSON 형식의 문자열을 object로 변환!

console.log(uesr.name) // John
console.log(user.age) // 30

이 때, 만약 서버에서 잘못된 json이 들어올 경우, JSON.pasre()에서 에러를 만들기 때문에
스크립트가 중지되게 된다. 서버에서 전달받은 데이터가 잘못되어 스크립트가 죽는 경우, 사용자는 개발자 콘솔을 열지 않는 이상 절대 원인을 알 수 없게된다. 그래서 try, catch를 이용해서 에러를 적절히 처리해줘야 한다.

let json = "{bad json}";

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

이 예시에서는 에러가 발생했다는 것만을 보여주지만, catch 블록 안에서는 새로운 네트워크 요청 보내기나 사용자에게 대안 제안하기 및 로깅 장치에 에러 정보 보내기 등과 같은 더 고차원적인 일을 할 수 있다.

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

throw 연산자는 에러를 생선하게 된다. 이론적으로 object 자리에 어떤 것이든 error object로 사용할 수 있다. 그러나 내장 에러와의 호환을 위해 여러 객체에 name과 message 프로퍼티를 넣어주는 것이 좋다.

자바스크립트에서는 Error, SyntaxError, ReferenceError, TypeError 등의 표준 에러 객체 관련 생성자를 지원한다. 이 생성자들로 여러 에러 객체를 만들 수 있다!

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

일반 객체가 아니라 내장 생성자를 사용해 만든 내장 에러 객체의 name 프로퍼티는 생성자 이름과 동일한 값을 가진다. 프로퍼티 message의 값은 인자에서 가져온다.

잘못된 데이터를 받았을 때, JSON.parse()가 어떤 종류의 에러를 만들어내는지 확인해보았다.
SyntaxError를 출력해주게 된다.
message는 Unexpected token e in JSON at position 1이라고 뜨게 된다.


사용자를 나타내는 객체에 name 프로퍼티는 반드시 있어야 하므로, 이제 name이 없으면 에러가 발생하는 것으로 간주하고 예외처리르 만들어 보았다. throw 연산자를 사용해 에러를 던져보자.

let json = '{"age":30}';

try {
	let user = JSON.parse(json);
    if (!user.name) {
    	throw new SyntaxError("not found user.name");
    } catch (error) {
    	console.log("error!", error.message);
}


// error! not found user.name (내가 입력했던 error.message가 뜬다)

throw 연산자는 message를 이용해 SyntaxError를 생성한다.
이렇게 JSON.parse()에서 에러가 발생한 경우를 포함해 모든 에러를 catch 블록 안에서 처리할 수 있다.


try, catch, finally

try, catch 구문에서 finally라는 코드 절을 하나 더 가질 수 있다.
finally 안의 코드는 다음과 같은 상황에서 실행된다.

에러가 없는 경우 : try 실행이 끝난 후
에러가 있는 경우 : catch 실행이 끝난 후

finally를 사용하면 try, catch 구문을 더 풍부하게 쓸 수 있다.

try {
	// ...
} catch (error) {
	// ...
} finally {
	// 항상 실행되는 코드
}

finally는 무언가를 실행하고, 실행 결과에 상관없이 실행하고 싶은 코드가 있을 때 사용하면 된다. 원한다면 catch 절 없이 try, finally 구문도 상황에 따라 유용하게 사용할 수 있다.
try, finally 구문은 에러를 처리하고 싶지는 않지만, 시작한 프로세스가 마무리 됐는지 확실히 확인하고 싶은 경우 사용하면 되겠다.

0개의 댓글