JS) try...catch 정리하기

winter100·2023년 10월 17일

자바스크립트

목록 보기
2/15
post-thumbnail

1. 예외처리 try...catch란

프로그래밍에서 다양한 이유로 에러가 발생하게되는데, 에러가 발생하게 되면 스크립트(쉽게 생각하면 프로그램을 구성하는 코드)는 중단되고 에러가 출력되게된다.

이런 상황을 유저가 겪게된다면 작업한 모든 내용을 잃을 수도 있게되고 다시는 프로그램을 사용하지 않게될 수 도있다.

이런 상황을 대처하기 위해서 자바스크립트에서는 try...catch를 이용해 예외(에러)가 발생했을때 후속처리를 통해 스크립트를 살리고 프로그램이 안정적으로 실행될 수 있도록 해준다.



2. try...catch 문법

try {

	//예외(에러)가 발생할 수 있는 코드
    
} catch (error) {

	//예외(에러)가 발생했을때 처리하는 코드
    
}

실행흐름은 다음과 같다.

  1. try { ... } 안의 코드가 실행된다.
  2. 에러가 없다면 try { ... } 안의 코드가 끝까지 실행되고 catch의 코드는 건너뛴다.
  3. 에러가 발생했다면 try { ... } 안의 코드는 실행이 중단되고 catch (error) { ... }로 제어 흐름이 넘어간다.
    (이때 catch의 error 매개변수에 에러의 설명이 담긴 에러 객체를 넘겨준다)

catch(error) { ... }의 변수명은 마음대로 정할 수 있다.
catch(e) { ... }, catch(err) { ... } 등등


에러가 발생하지 않은 코드

try {
  
  console.log("코드 시작"); // 코드 시작
  
} catch (e){
  
  console.log("에러 발생"); // 에러가 발생하지 않아 실행되지 않음
  
}

에러가 발생한 코드

try {
  
  console.log("코드 시작"); // 코드 시작
  abcd(); //선언하지 않은 함수 실행으로 에러 발생, 코드실행이 중지되고 catch로 제어권이 넘어감 
  console.log("코드 끝"); // 이 코드는 실행되지 않음
  
} catch (e){
  
  console.log("에러 발생"); // 에러 발생
  
}

위 코드처럼 에러가 발생하더라도 예외처리를 통해 프로그램이 강제로 종료되지 않고 적절한 조치를 취할 수 있게된다.


try....catch는 동기적으로 동작한다.

try {
  
  console.log("1"); // 1

  setTimeout(function() {
    console.log("2"); // 1과 3 출력 후 1초 뒤에 2가 출력
    abcd(); // 선언하지 않은 함수 실행 에러 발생
    console.log("코드 끝"); // 실행되지 않음
    
  }, 1000);
  
  console.log("3"); // 3

} catch (e) {
  
  console.log("에러 발생"); // 해당 코드는 실행되지 않음
  
}

위 코드가 잘 작성되어 있는 것처럼 보이지만 사실은 그렇지 않다.

  • try 블록의 코드는 동기적으로 실행되기 때문에 setTimeout과 같은 함수에 전달된 콜백 함수는 try 블록을 떠나기 전에 예약되지만, 그 콜백의 실행은 try를 벗어난 후에 비동기적으로 실행된다.
  • 따라서 보기에는 try블록 안이지만 처리는 try블록을 벗어난 후 setTimeout이 실행 되기 때문에 try...catch에서 예외처리하지 못한다.

그럼 어떻게해야 할까?

방법은 간단하다. 비동기적인 함수내에 다시 try...catch를 이용해 예외처리를 해주면 된다.

try {
  
  console.log("1"); // 1

setTimeout(function() {
    try {
      
        // 비동기 작업, 예외가 발생할 수 있는 작업
      	console.log("2"); // 2
      	abcd(); // 함수가 정의되어 있지 않음 에러 발생
     	console.log("코드 끝"); // 실행되지않음
      
    } catch (error) {
      
        console.log("비동기 코드 내에서 에러 발생"); // 비동기 코드 내에서 에러 발생
      
    }
}, 1000);
  
  console.log("3"); // 3

} catch (e) {
  
  console.log("에러 발생"); // 해당 코드는 실행되지 않음
  
}
  • 1과3이 콘솔에 찍힘
  • 비동기함수가 1초뒤 실행되고 2가 콘솔에 찍힌 후 에러가 발생
  • 비동기함수내의 catch문으로 제어권이 넘어가 콘솔에 "비동기 코드 내에서 에러 발생"가 찍힌 후 실행이 종료된다.

3. 에러 객체

try...catch는 에러가 발생하게 되면 에러의 내용이 담긴 객체를 생성한 뒤 catch(e)의 인수로 전달해준다.

일반적으로 이런 예외가 발생했을 때 전달받은 에러 객체에는 몇가지 기본 프로퍼티가 제공되는데 다음과 같다.

  • name : 에러의 이름을 나타낸다.
  • message : 에러에 대한 상세한 설명이 포함된다.
  • stack : 에러가 발생한 위치에 대한 스택 트레이스 정보를 포함하며 디버깅에 유용하다.
try {
  
  console.log("코드 시작"); // 코드 시작
  abcd(); // 에러 발생, catch로 에러 객체와 함께 제어권이 넘어감
  console.log("코드 끝") // 실행되지 않음

} catch (e) {
  
  console.log("에러 발생"); // 에러 발생
  console.log(e); //e: ReferenceError: abcd is not defined
  console.log("name: " + e.name); // name: ReferenceError
  console.log("message: " + e.message); // message: abcd is not defined
  console.log("stack: " + e.stack);
  // stack: ReferenceError: abcd is not defined
  // at neyozodate.js:4:3
  // at https://static.jsbin.com/js/prod/runner-4.1.8.min.js:1:13924
  // at https://static.jsbin.com/js/prod/runner-4.1.8.min.js:1:10866
  
}

에러 만들기

try...catch문에서 에러가 발생하면 catch로 제어권이 넘어감과 동시에 에러 객체를 전달해준다는걸 알았다. 그럼 이걸 이용해서 에러가 발생했을때 핸들링 하는걸 알아보자.

throw : 사용자 정의 예외를 발생시킨다.

throw "Error"; // 문자열 "Error"를 갖는 예외 발생
throw 20; // 20값을 갖는 예외 발생
throw true; / true값을 갖는 예외 발생

이 처럼 throw 이후 값을 적어주면 해당 예외가 발생하지만 이런식으로 예외가 발생하면 무엇을 의미하는지 알수 가 없기 때문에 자바스크립트의 표준 에러 객체 관련 생성자를 이용해 에러 객체를 만든다.

let error = new Error(message);
	''    = new SyntaxError(message);
	''    = new ReferenceError(message);

Error, SyntaxError, ReferenceError 등과 new를 이용해 에러 객체를 생성한다.

try {
  const num = 2;
  if(num % 2 === 0){
    throw new Error("짝수 에러를 발생시킵니다.")
  }
  console.log("코드 끝"); // 실행되지 않음
  
} catch (error){
  
  console.log(error.name); // "Error"
  console.log(error.message); // "짝수는 에러를 발생시킵니다."

에러 객체 관련 생성자를 이용해 에러 객체를 만든다면 name은 생성자의 이름 message는 인수값이 된다. 위 코드에서는
throw new Error("짝수 에러를 발생시킵니다.") 중에서

Error <-이게 name값으로.

("짝수 에러를 발생시킵니다.") <-이게 message값이 된다.


에러 다시 던지기

어떤 에러가 발생할지 모두 예측하고 처리해주면 좋겠지만 사실 거의 불가능하다고 봐야한다. catch에서는 알고 있는 에러만 처리하고 나머지는 다시 에러를 던져줘야 한다.

  1. catch가 모든 에러를 받는다.
  2. catch(error)에서 error을 분석하고 에러를 처리한다.
  3. 에러 처리방법을 모른다면 다시 throw error을 한다.

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

function readData(){
  let json = '{ "age": 30 }'; // 불완전한 데이터
  
try {
  let user = JSON.parse(json);
  if (!user.age) {
    throw new SyntaxError("불완전한 데이터: 나이없음");
  }

  abcd(); // 예상치 못한 에러
  alert( user.age ); //실행되지않음

} catch(e) {

  if (e instanceof SyntaxError) {
    alert( "JSON Error: " + e.message ); // 이 코드는 ReferenceError에러이다. 때문에 실행되지 않음
  } else {
    console.log(e.name) // ReferenceError
    throw e; // 에러 다시 던지기
  }
 }
}

try{
  readData();
} catch(e){
  alert("에러 다시 잡기"); //alery로 "에러 다시 잡기"가 뜸
}

위 코드에서는 나이가 없는 json 데이터가 들어오면 SyntaxError에러를 발생시키고 해당 함수 내에서 처리를 한다. 그외에 알 수 없는 에러는 다시한번 throw를 하게 된다.
위 코드를 실행하면 alert창으로 "에러 다시 잡기" 가 뜨게 된다.

이런 식으로 처리할 수 있는 에러만 처리한 뒤 모르는 에러는 다시 던져야 스크립트가 죽는 것을 최소한으로 줄일 수 있게 된다.


try...catch...finally

try...catch는 finally 라는 코드를 하나 더 사용 할 수 있다.
finally 코드는 다음와 같은 경우 실행된다.

  • 에러가 없음: try 실행이 끝난 후,
  • 에러가 있음: catch 실행이 끝난 후,

이 두 경우 finally가 실행되고 코드는 종료 된다.

에러가 없는 코드

try{
  
  console.log("코드 시작"); // 코드 시작 (1)
  
} catch(e){
  
  console.log("에러 발생") // 실행되지 않음
  
} finally{
  
  console.log("finally 실행") // finally 실행 (2)
  
}

에러가 있는 코드

try{
  
  console.log("코드 시작"); // 코드 시작 (1)
  abcd(); // 에러 발생 제어권이 catch로 넘어감
  console.log("코드 끝"); // 실행되지않음
  
} catch(e){
  
  console.log("에러 발생") // 에러 발생 (2)
  
} finally{
  
  console.log("finally 실행") // finally 실행 (3)
  
}

finally는 return을 사용해 빠져 나가더라도 실행된다. 또한 return이 반환되기 전에 finally가 실행된다.

function testData(){
  
  try{
    alert("코드 시작"); // 코드 시작 (1)
    return "20리턴";
  
} catch(e){
  
  console.log("에러 발생") // 실행되지않음
  
} finally{
  
  alert("finally 실행"); // finally 실행 (2)
  
}
}

alert( testData() ); // 20리턴 (3)

선택적 catch 바인딩

try {
    // 예외가 발생할 수 있는 코드
} catch {
    // 예외를 처리하는 코드 (e)없이 작성
    console.log("예외를 처리했습니다.");
}
  • 최근에 추가된 것 인데 에러에 대한 정보가 필요하지 않으면 선택적 catch 바인딩을 이용할 수 있다.
  • 구식 브라우저는 폴리필이 필요하다
    폴리필: 브라우저가 지원하지 않는 자바스크립트 코드를 지원 가능하도록 변환한 코드

혼자 알아보고 정리 했지만 틀린게 많을 수 있습니다. 무엇이든 좋으니 피드백 부탁드립니다.

출처

모던 자바스크립트 - try...catch
JavaScript - MDN

0개의 댓글