JavaScript 공부 9주차

sdtana·2021년 6월 19일
0

학습할 것

  • 자바 스크립트가 제공하는 예외 계층 구조
  • 예외 처리 구문 없이 예외를 처리하는 법.
  • 적절한 예외 처리는 어떻게 해야할까?
  • 최근 예외 처리 동향 (꼭 JS가 아니여도 됨)

예외를 발생시키는 이유

에러 없는 코드를 작성하는 것은 불가능하다. 즉 에러는 언제나 발생할 수 있다. 에러가 발생하면 프로그램은 강제 종료되므로 이를 피하기 위해 발생한 에러에 예외 처리를 하여 대처할 수 있다.

예외는 꼭 발생시켜야 하는 것일까?

  • 예외를 발생 시켜야 하는 상황
    ex) 로그인 실패, 데이터 조회 실패
    프로그램에서 당연히 발생 할 수밖에 없는 상황이므로 예외 처리를 하여야 함
  • 예외를 발생 시키지 말아야 하는 상황
    ex) 버그, 시스템 메모리 문제
    프로그램의 비정상적인 동작이므로 예외처리가 아닌 코드 개선이 필요함

오류의 종류들

오류의 종류에는 구문 오류(Syntax Errors, Parsing errors), 런타임 오류(Runtime Errors, Exceptions), 논리적 오류(Logical Errors)가 있다.
구문 오류는 JavaScript의 인터프리트 시간에 발생한다. 예를 들어 다음 코드는 닫는 괄호가 없기 때문에 구문 오류가 발생한다.

console.log('hello world' //SyntaxError: missing ) after argument list

런타임 오류는 코드 실행 중에 발생한다. 구문 오류와는 달리 코드에는 오류가 없다.
예를 들어 다음 코드는 구문에 오류는 없지만 정의하지 않은 식별자를 호출하였기 때문에 런타임 오류가 발생한다.

foo(2,2); // ReferenceError: sum is not defined

논리적 오류는 프로그래밍 중 논리적인 실수가 있어 예상한 결과를 얻지 못알 때 발생한다. 인터프리터에 감지되지 않으며 결과가 나온 후에야 오류를 확인할 수 있기 때문에 추적하기 가장 어려운 유형이라 할 수 있다.

에러 오브젝트

Error 생성자 함수는 에러 메세지를 전달하는 message 프로퍼티와 에러가 생성된 콜 스택의 호출 정보를 제공하는 stack 프로퍼티 그리고 에러 이름을 제공하는 name 프로퍼티가 있다.
또한 JavaScript는 Error 생성자 함수에 7가지의 에러 오브젝트를 제공하는데 일반적 에러 객체인 Error, 문법에 맞지 않는 문을 해석할 때 발생하는 에러 객체인 SyntaxError, 참조할 수 없는 식별자를 참조했을 때 발생하는 에러 객체인 ReferenceError, 피연산자 또는 인수의 데이터 타입이 유효하지 않을 때 발생하는 에러 객체인 TypeError, 숫자값의 허용 범위를 벗어났을 때 발생하는 에러 객체인 RangeError, encodeURI 또는 decodeURI 함수에 부적절한 인수를 제공했을 때 발생하는 에러 객체인 URIError, eval 함수에서 발생하는 에러 객체인 EvalError가 있다.

1 @ 1; // SyntaxError: Invalid or unexpected token
foo(); // ReferenceError: foo is not defind
null.foo; // TypeError: Cannot read property 'foo' of null
new Array(-1); // RangeError: Invalid array length
decodeURIComponent(%); // URIError: URI malfromed

자바 스크립트가 제공하는 예외 계층 구조

자바스크립트에서 예외 처리 방법

try...catch...finally 구문

try...catch...finally 문을 실행하면 먼저 try 코드 블록이 실행된다. 이후 try 코드 블록의 문에서 에러가 발생하면 발생한 에러는 catch 문의 err에 전달되고 catch 코드 블록이 실행된다. finally 코드 블록은 반드시 한 번 실행되며 불필요하다면 생략할 수 있다. catch 구문 또한 생략 가능하지만, try 구문 혼자서는 별 의미가 없으므로 사용하지 않는다.

try{
  // 실행할 코드 (에러가 발생할 가능성이 있는 코드)
  foo();
} catch (err) {
  // try 코드 블록에서 에러가 발생하면 이 코드 불록의 코드가 실행된다.
  // err에는 try 코드 블록에서 발생한 Error 객체가 전달된다.
  console.error(err); // ReferenceError: foo is not defined
} finally {
  // 에러 발생과 상관없이 이 코드가 실행된다.
}

throw 구문

Error 생성자 함수로 에러 객체를 생성한다고 에러가 발생하는 것은 아니다. 에러 생성과 에러 발생은 의미가 다르다고 할 수 있다.
에러를 발생시키려면 try 코드 블록에서 throw 문으로 에러 객체를 던져야 한다.

try {
  // throw 표현식;
  throw new Error('something wrong');
} catch (err) {
  console.log(err) // Error: something wrong 
}

throw 문의 표현식은 어떤 값이라도 상관없지만 일반적으로 에러 객체를 지정한다.

그 외의 방법

비동기 상황에서는 try...catch...finally 구문이 동작하지 않는다. 코드가 바로 콜스택에 들어가는 것이 아니라 작업 큐에서 대기를 하기 때문이다. 따라서 예외가 발생하는 시점과 try가 싸고 있는 시간대가 달라 try 구문이 작동하지 않는다.

.catch 메서드

Promise가 포함되어 있는 함수 실행부 뒤에 .catch() 메서드를 사용하여 에외 처리를 할 수 있다. .catch() 메서드는 프로미스가 reject 상태일 경우에만 호출된다.

function wait(sec) { 
    return new Promise((resolve, reject) => { 
        setTimeout(() => { reject('error!'); 
        }, sec * 1000);
    });
} 
 wait(1).catch(e => { console.log('1st catch ', e); });
// 1st catch  error!

.then() 메서드

.then() 메서드는 .catch 메서드와 비슷하게 동작하는데, 첫 번째 콜백 함수는 비동기 처리가 성공했을 때, 두 번째 콜백 함수는 비동기 처리가 실패했을 때 호출된다.

new Promise((_, reject) => reject(new Error('ThisIsError')))
.then(v => console.log(v), e => console.error(e));
//Error:ThisIsError

커스텀한 예외 만드는 방법

코드 작성 시 자체적으로 에러 클래스를 생성할 경우가 있다. throw의 인수에서는 제약이 없기 때문에 Error를 상속할 필요가 없지만 호환성을 위해 Error 생성자 함수를 상속받는다.

class CustomError extends Error {
    constructor(message) {
        super(message);
        this.name = "CustomError";
    }
}

try {
    throw new CustomError('에러 발생');
} catch (err) {
    console.error(err); // CustomError: 에러 발생
}

예외 처리 구문 없이 예외를 처리하는 법

적절한 예외 처리는 어떻게 해야할까?

참조

profile
귀차니즘 탈출 시도중

0개의 댓글