예외처리란?( + 적용)

성찬홍·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 객체로 쿼리를 실행할 때 에러가 발생하면 errorthrow하는 형태이며, 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일

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

답글 달기