async/await 문법으로 예외 처리를 할 때 저지른 실수

박기완·2021년 9월 16일
1

async/await 문법과 try/catch 구문을 섞어 쓰면서 했던 실수를 기록한다.

에러가 발생할 수 있는 비동기 함수가 있고, 그 함수에서 발생하는 에러를 처리하고 싶었다. 그래서 다음과 같은 코드를 작성했다.

async function getValue() {
  try {
    return myAsyncFunction();
  } catch (error) {
    console.error(error);
    return undefined;
  }
}

이렇게 하면 myAsyncFunction 실행중 발생한 에러가 잡혀서 getValue 함수는 undefined를 반환할 것이라고 생각했다. 하지만 getValue 함수 바깥으로 계속 에러가 던져지고 있었다.

코드를 좀 더 유심히 바라보다 원인을 알게 되었는데, 함수의 실행 결과를 바로 리턴하는 것이 문제였다. myAsyncFunction은 비동기 함수이니까 Promise를 반환할 테고, getValue도 같은 Promise 객체를 반환할 뿐이다. Promise의 최종 계산은 getValue를 await하고 있는 지점에서 이뤄지니까 에러는 잡히지 않는다.

이를 원하는 대로 작동하게 만들려면 getValue에서 myAsyncFunction의 Promise를 resolve 해줘야 한다.

async function getValue() {
  try {
    const value = await myAsyncFunction();
    return value;
  } catch (error) {
    console.error(error);
    return undefined;
  }
}

Promise의 "await"을 위한 변수 선언이 눈에 띈다. 왜냐면 return await은 린트 규칙으로 막고 있었거든.

(2021년 10월 13일 업데이트)
no-return-await 규칙return await를 무조건 막는 줄 알았는데 아니었다. try/catch 안의 return await은 허용하고 있었다. 그냥 내가 이렇게 코딩해야하는 것을 모르고 있었을 뿐...
따라서 다음과 같은 형태를 쓸 수 있다.

async function getValue() {
  try {
    return await myAsyncFunction();
  } catch (error) {
    console.error(error);
    return undefined;
  }
}

에러는 항상 발생하는 것이 아니라 잘못 코딩한 것을 지나치기 쉽다. 테스트 코드를 잘 짜던지, 아니면 더글라스 크락포드 형님이 말씀하셨듯 정말 예상치 못한 상황에서만 에러를 발생하게 함수를 설계해야겠다.


아예 async/await 문법을 쓰지 말아볼까...?

myAsyncFunction({
  onSuccess: (value) => {
    handleValue(value)
  },
  onFail: (error) => {
    console.error(error)
    handleValue(undefined)
  },
})

결과를 기다리기 위한 변수 선언이 없고, 모든 걸 함수로 표현한다는 장점이 느껴진다. 하지만 콜백 헬이 두렵기도 하고... 아직 async/await이 편해보인다. 🤔

0개의 댓글