[JavaScript] 예외처리

Letmegooutside·2022년 1월 31일
0

JavaScript

목록 보기
24/25
post-thumbnail

throw

예외를 강제로 발생시켜야하는 경우가 생길 때 사용하는 키워드

throw 표현식;

표현식의 결과 값 타입은 무엇이든 될 수 있다.
하지만 대부분의 그 타입은 Error객체 또는 Error의 하위 클래스 중 하나의 인스턴스가 된다.
에러 메시지를 담고 있는 문자열이나, 에러 코드를 나타내는 숫자 값으로도 사용할 수 있다.

function factorial(x) {
  // 전달 인자가 유효하지 않으면 예외를 발생시킨다.
  if(x < 0) {
    throw new Error('x는 음수가 아니어야 합니다.');
  }
  // 유효하다면 값을 계산하여 정상적으로 반환
  ...
}

예외가 발생하면 자바스크립트 인터프리터는 정상적인 프로그램 실행을 즉시 중단하고 가장 가까운 예외처리기로 넘어간다.
예외 처리기는 catch절을 사용하여 작성된다.

예외를 발생시켰던 코드 블록이 catch절과 연결되어 있지 않으면, 인터프리터는 바로 상위 단계를 감싸고 있는 코드 블록에 연결되어 있는지 확인한다.

Call Stack을 따라서 예외가 전파되어 올라가는데 아무런 예외 처리기도 찾을 수 없으면 이 예외는 에러로 취급되어 사용자에게 보고되어 진다.

예외를 강제로 발생시키는 이유?

객체를 잘못 사용하는 사용자에게 예외를 강제로 발생시켜 주의를 줄 수도 있고 예외와 관련된 처리를 해달라고 부탁할 수도 있다.

try/catch/finally

자바스크립트의 예외 처리 기법이다.

try {
  예외 처리를 원하는 코드;
}catch (e) {
  예외가 발생할 경우 실행될 코드;
} finally {
  try 블록이 종료되면 예외 발생 여부와 상관없이 무조건 실행될 코드;
}

catchfinally블록은 선택적인 옵션으로 반드시 사용할 필요는 없다.

Error 객체

자바스크립트에서는 런타임 오류가 발생할 때 마다 Error객체의 인스턴스가 생성되어 해당 오류의 정보를 저장한다.

function throwEx() {

    try {
		// Error 객체를 사용해 명시적으로 오류를 발생시킴.
        throw new Error("직접 발생시킨 오류입니다!"); 
	// 발생된 오류를 매개변수 e로 접근할 수 있음.
    } catch (e) { 
      // name 프로퍼티는 오류의 타입을 저장함.
      console.log(e.name);
      // message 프로퍼티는 오류 메시지를 저장함.
      console.log(e.message);
    }
}

비동기 상황에서의 예외처리

비동기 작업은 바로 Call Stack에 들어가는 것이 아니라, Callback Queue에서 대기했다가 Call Stack이 비워지면 Call Stack으로 들어와 실행된다.
따라서 예외가 발생하는 시점과 try문이 감싸고 있는 시간이 일치하지 않게 되므로 try/catch구문으로 에러를 잡을 수 없다.

Promise의 .catch()

function wait(sec) { 
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('error!');
    }, sec * 1000);
  });
}

wait(3).catch(e => {
  console.log('1st catch ', e);
}); 

// chain 을 하고 싶을 때
wait(3).catch(e => {
  console.log('1st catch ', e);
  // 같은 에러를 발생시켜 다음 catch구문에서 잡을 수 있도록 해준다.
  throw e;
})
.catch(e => {
  console.log('2st catch ', e);
});

Promise가 포함되어 있는 함수 실행부 뒤에 .catch()를 통해 에러를 잡아주면 된다.
이 때 주의할 점은 .catch구문은 .then()처럼 체이닝할 수 없다는 점이다.

첫번째 catch구문 이후의 catch구문은 원래 함수의 결과를 받는 것이 아니라 이전 catch구문의 실행 상태를받기 때문에 체이닝 하려면 리턴하는 객체가 같아야 한다.

Promise의 .then() 이용하기

wait(3).then(() => {
  	// 성공했을 경우
    console.log('Success');
}, e => {
  	// 실패했을 경우
    console.log('Catch in Then ', e);
})

then을 이용하여 성공했을 경우(resolve), 실패했을 경우(reject)로 나눠서 처리를 해줄 수도 있다.

Async/await의 에러처리

async function myAsyncFunc() {
  return 'done';
}
const result = myAsyncFunc();
console.log(result); // Promise { <resolved>: "done" }

async함수의 리턴 값은 Promise객체의 인스턴스이다.
따라서 함수에서 에러가 발생하지 않고 실행에 성공했을 경우 resolved 프로퍼티가 반환되므로 Promise와 동일하게 에러처리를 해주면 된다.

async function myAsyncFunc() {
  throw 'myAsyncFunc Error!';
}

const result = myAsyncFunc().catch(e => { console.log(e) });

그리고 await를 사용했을 경우 try/catch 또는 .catch를 사용하면 된다.
await 구문을 사용하게 되면 에러가 발생되는 시점이 try가 감싸고 있는 시간과 일치하기 때문이다.

async function myAsyncFunc() {
  try {
    await wait(2); // Promise를 기다리는 중...
  } catch (e) { 
    console.error(e); 
  }
}

const result = myAsyncFunc();



Reference
https://ebbnflow.tistory.com/268
http://www.tcpschool.com/javascript/js_exception_exception
https://webclub.tistory.com/71

0개의 댓글