예외처리란?( + 적용)

성찬홍·2023년 8월 6일

Code Refactoring

목록 보기
4/5

1. 예외 처리란?

  • 코드 실행 중에 예기치 못한 에러가 발생했을 때, 이로부터 코드의 실행 흐름을 복구할 수 있는데 이를 예외 처리(Exception Handling)라고 한다.

  • JavaScript는 기본적으로 싱글 스레드이므로 스레드가 멈춘다는 것은 프로세스가 멈추는 것이어서 예외 처리는 필수이다.

2. JavaScript의 예외 처리 방법

& try-catch-finally

try...catch...finally 구문을 사용하여 에러가 나더라도 코드의 실행을 지속할 수 있다.

ex) try-catch

try {
  console.log('에러가 나기 직전까지의 코드는 잘 실행됩니다.');
  new Array(-1); // RangeError: Invalid array length
  console.log('에러가 난 이후의 코드는 실행되지 않습니다.');
} catch (e) {
  console.log('코드의 실행 흐름이 catch 블록으로 옮겨집니다.');
  alert(`다음과 같은 에러가 발생했습니다: ${e.name}: ${e.message}`);
}

→ 에러가 났을 때 원상 복구를 시도하려면 try 블록 내부에 작성하면 된다. 에러가 발생했을 때 코드의 실행 흐름이 try 블록에서 catch 블록으로 옮겨 간다. 이때 catch 블록 안에서는 에러에 대한 정보를 담고 있는 객체 e를 사용할 수 있다.

ex) try-finally

for (let i of [1, 2, 3]) {
  try {
    if (i === 3) {
      break;
    }
  } finally {
    console.log(`현재 i의 값: ${i}`);
  }
}

→ finally 블록이 사용되면 try 블록 안에서의 에러 발생 여부와 관계없이 무조건 실행된다.
→ finally 블록은 catch 블록과도 함께 사용된다.
→ 에러가 안 났을 때: try-finally
→ 에러가 났을 때: try - 에러 발생 - catch - finally

ex) Error 생성자와 throw(에러 직접 발생시키기)

const even = parseInt(prompt('짝수를 입력하세요'));
if (even % 2 !== 0) {
  throw new Error('짝수가 아닙니다.');
}

→ 에러의 종류를 구분해야 하거나 에러 객체에 기능을 추가해야 할 필요가 있을 때 사용한다.

ex) 비동기 코드에서의 에러

(1) Promise의 경우

Promise.resolve()
  .then(() => {
    throw new Error('catch 메소드를 통해 예외 처리를 할 수 있습니다.');
  })
  .then(() => {
    console.log('이 코드는 실행되지 않습니다.');
  })
  .catch(e => {
    return e.message;
  })
  .then(console.log);

→ 기존 try-catch 블록에 넣을 경우에는 try 블록이 비동기 함수에서 발생한 에러를 처리할 수 없다.
→ 그래서 위와 같이 비동기 콜백의 내부에 try 블록을 작성해 줘야 한다.
→ then 메서드의 연쇄 안에서 에러가 발생하면 try...catch 구문과 유사하게 처음 만나는 에러 처리 콜백으로 코드의 실행 흐름이 건너뛰게 된다.

(2) async-await 사용의 경우

async function func(){
	try{
		const res = await fetch("https://~~");
	}
		catch(e){
		console.log(e.message);
	}
}
func(); // Failed to fetch

→ async-await 형태를 사용하면 위의 체인 형태의 복잡한 구조를 좀 더 단순하게 만들 수 있다.


3. 내 코드에서의 적용

프로젝트를 진행하면서 백엔드에서 MySQL 연동 관련 API를 호출할 때 요청 파라미터가 전달되지 않는 오류를 가장 많이 받았습니다.
그래서 이 부분에 대해서 에러 처리를 해 볼 예정입니다.

(1) 기존 코드

MySQL connection 객체로 쿼리를 실행할 때 에러가 발생하면 error를 throw하는 형태이며, SQLdata에 값이 제대로 들어오지 않았을 때 에러가 발생하고 서버가 중단됩니다.

getClubDetailInfo: async (req, res) => {
    const selectSQL = `SELECT * FROM CLUB_TABLE WHERE C_IDX =?`;
    const SQLdata = [req.query.data];

	connection.query(seletSQL, SQLData, (error, result) => {
      if (error) throw error;
      res.status(200).send(result);
    });

  }

(2) 수정 후 코드

아래처럼 수정한 후로 SQLdata에 문제가 생기더라도 서버는 중단되지 않으며, 상태 코드로 현재 문제만 전달받을 수 있게 되었습니다.
이 외의 API 코드도 대부분 수정 전 코드와 같이 구성되어 있어서 아래와 같이 수정하였습니다.

getClubDetailInfo: async (req, res) => {
    const selectSQL = `SELECT * FROM CLUB_TABLE WHERE C_IDX =?`;
    const SQLdata = [req.query.data];

    try {
      // 기존 SQLdata 문제를 null, undefined 체크를 통해 미리 확인하여,
      // 문제 발생 시 TypeError를 던져 주고 아래 실행문은 실행되지 않으며,
      // catch문으로 넘어가 상태 코드 405를 클라이언트로 전달해 준다.
      if (req.query.data === null || req.query.data === undefined)
        throw TypeError("SQLdata Null Error");
      connection.query(selectSQL, SQLdata, (error, result) => {
        if (error) throw error;
        res.status(200).send(result);
      });
    } catch (error) {
      if (error instanceof TypeError) {
        res.status(405).send("SQL Error");
      } else {
        res.status(406).send("Error :" + error);
      }
    }
  }

4. 느낀 점

사이트를 만들면서 try-catch 구문이 예외 처리문이라는 정도는 알고 있었지만, 제대로 된 처리를 하지 않은 상태였습니다.

이번에 적용하면서 가장 많이 받았던 오류를 떠올려 처리해 주었는데, 아직 제가 생각하지 못한 예외 처리 부분들이 많을 것 같습니다.
좀 더 처리해야 할 부분이 생기면 바로바로 업데이트해 나가야겠다는 생각이 들었습니다.

https://helloworldjavascript.net/pages/290-exception.html
https://www.youtube.com/watch?v=EBmIHrLTVdg&ab_channel=코드종

profile
꾸준한 개발자

1개의 댓글

comment-user-thumbnail
2023년 8월 6일

많은 것을 배웠습니다, 감사합니다.

답글 달기