[JS] 에러 핸들링

Yuno·2021년 5월 14일
0

모던JS

목록 보기
6/16
post-thumbnail

아무리 능한 사람이라도, 에러있는 스크립트를 작성할 수 있습니다.
원인은 실수, 예상치 못한 사용자 입력, 잘못 된 서버 응답 등이 될 수 있습니다.

스크립트에서 에러가 발생하면, 스크립트는 죽고(중단되고) 콘솔에 에러가 출력됩니다.

그러나 try...catch를 통해 스크립트가 죽는걸 방지하고,
에러를 잡아서(catch) 더 나은 무언가를 할 수 있습니다.

try...catch

trycatch 두개의 주요 블록으로 구성됩니다.

try {
  // 코드
}
catch (err){
  // 에러 핸들링
}

try내의 코드가 실행되고, 에러가 없다면 끝까지 실행된 후 catch는 무시됩니다.
에러가 있다면, 실행이 중단되고, catch 블록으로 흐름이 넘어갑니다.
err은 무슨일이 일어났는지에 대한 '에러 객체'를 포함합니다.

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

중괄호 짝이 안 맞는 등 문법적으로 잘못되면, 동작하지 않습니다.

자바스크립트 엔진은 코드를 읽고, 코드를 실행합니다.
읽는 중에 생긴 에러는 parse-time 에러라고 부르는데, 코드를 이해할 수 없기 때문에,
코드 안에서 복구가 불가능합니다.

try...catch는 유효한 코드에서의 에러만 처리하며,
이를 런타임 에러, 예외(Exception) 라고 부릅니다.

try...catch는 동기적으로 작동합니다.
setTimeOut처럼 스케줄된 작업은 처리하지 못합니다.

에러객체

에러가 발생하면 자바스크립트는 에러 상세내용이 담긴 객체를 생성합니다.

두가지 주요 프로퍼티를 가집니다.

  • name : 에러의 이름
  • message : 에러의 상세 내용 메시지

표준은 아니지만, 대부분의 호스트 환경에서 제공하는 프로퍼티 stack

  • stack : 현재 호출 스택, 에러를 유발한 중첩 호출들의 순서 정보

선택적 catch 바인딩

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

try{
    // 코드
}
catch{ // -> (err) 생략
    // 핸들링
}

try...catch사용 예제

JSON으로 인코딩 된 값을 읽을 수 있게 해주는 JSON.parse(str) 메소드는
주로 서버에서 전달받은 데이터를 디코딩 할 때 사용합니다.

다만, 잘못된 형식이 들어온 경우, JSON.parse()는 에러를 만들어 스크립트가 죽습니다.

let json = "{ bad json }";

try {
  let user = JSON.parse(json); // <-- 에러 발생
  alert( user.name ); 

} catch (e) {
  // 에러가 발생하면 제어 흐름이 catch 문으로 넘어옵니다.
  alert( e.name );
  alert( e.message );
}

직접 에러 던지기

위와 같은 예시에서, json이 문법적으로 잘못되진 않았지만, 필수 프로퍼티를 가지지 않았다면

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

try {
  let user = JSON.parse(json); // <-- 에러X
  alert( user.name ); // undefined

} catch (e) {
  
}

이처럼 에러가 발생하지 않지만, user.name이 없는 건 에러를 유발하는 상황입니다.

throw 연산자

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

문법은 다음과 같습니다.

throw <error obeject>

원시형을 포함한 어떤 것도, 에러 객체가 될 수 있으나,
호환을 위해 name, message 프로퍼티를 포함하는 것이 좋습니다.

일반 객체가 아닌 내장 생성자를 이용할 수 있습니다.

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

name은 생성자명, message는 인자에서 받습니다.

이제 앞 상황에서 throw 연산자를 통해 에러를 던집니다.

let json = {age:24} // name이 없음
try{
	let user = JSON.parse(json);
  
  	if(!user.name) throw new SyntaxError('불완전한 데이터:이름 없음'); // 에러
	
  	alert( user.name );

} catch(e) {
  	alert( "JSON Error: " + e.message );
}

throw와 만나고, try가 중단된 후, 흐름이 catch로 넘어갑니다.
JSON 에러를 포함한 모든 에러를 catch블럭에서 처리하게 됩니다.

에러 다시 던지기

위에서 불완전한 JSON 데이터를 try...catch로 처리했습니다.
그러나, try 블럭 내에선 예기치 않은 변수가 발생할 수 있습니다.

위 예시에서 불완전한 데이터를 다루려는 목적으로 try...catch를 썼습니다.
그런데, catchtry블럭에서 발생하는 모든 에러를 잡으려는 목적으로 만들어졌습니다.

위에서 catch는 모든 에러를 잡았지만, 예기치 못한 상황에서도, JSON Error로 처리가 됩니다.

이러한 문제를 피하고자 다시 던지기 기술을 사용합니다.
catch는 알고 있는 에러만 처리하고 다시 던져야 합니다.

  1. catch는 모든 에러를 잡습니다.
  2. catch 블럭 내에서 에러 객체를 분석합니다.
  3. 에러 처리 방법을 알지 못하면, throw err합니다.

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

catch(err){
	if(!(err instanceof SyntaxError)) {
    	throw err // 다시던지기
    }
  
    // SyntaxError Handling
}

try{
	readData()
}catch(err){
	alert('external Error :' + err); // 에러를 잡음
}

다시 던져진 에러는 밖으로 던져집니다.
여기서 바깥에 try...catch가 있다면 거기서 잡고, 없다면 스크립트가 죽을 것 입니다.

이렇게 하면 catch 블록에선 다룰 수 있는 에러만 처리하고 나머지는 건너뛸 수 있습니다.

try...catch...finally

try...catchfinally라는 코드 절을 하나 더 가질 수 있습니다.
에러와 관계없이 항상 실행 되며,
에러가 없을 때는, try 실행 후,
에러가 있을 때는, catch실행 후에 실행됩니다.

try..catch...finally안의 변수는 지역변수 입니다.

profile
web frontend developer

0개의 댓글