자몽이 조아

try catch finally 는 항상 비동기를 기다리지 않는다 본문

개발공부/Javascript

try catch finally 는 항상 비동기를 기다리지 않는다

Grapefruitgreentealoe 2025. 2. 8. 15:43
반응형

개요

JavaScript의 try...catch...finally 구문을 사용할 때, finally 블록이 항상 비동기 코드가 끝날 때 실행된다고 착각하는 경우가 많다. 하지만 finally 블록은 try가 종료되면 즉시 실행되며, 내부의 비동기 코드가 완료되길 기다리지 않는다. 이를 이해하지 못하면 로딩 상태 관리나 비동기 작업의 순서를 제어하는 데에서 문제가 발생할 수 있다.

문제 상황

아래의 슈도코드를 살펴보자. 이 코드는 네트워크 요청을 수행한 후, 데이터를 다운로드하는 동안 로딩 상태를 표시하려는 의도로 작성되었다.

function downloadFile() {
  setLoading(true); // 로딩 시작
  try {
    fetchDataFromServer() // 비동기 요청
      .then((response) => response.blob())
      .then((blob) => {
        const url = createDownloadUrl(blob);
        triggerDownload(url, "output.pdf");
      })
      .catch(handleError);
  } finally {
    setLoading(false); // 로딩 종료
  }
}

이 코드를 실행하면 예상과 달리 로딩 상태가 즉시 false로 바뀌어 버린다. 왜 그럴까?

원인 분석

  • fetchDataFromServer()는 비동기 함수이므로 즉시 실행되지 않고, 프로미스를 반환한다.
  • 하지만 try 블록이 실행된 후 바로 finally 블록이 실행된다.
  • finally 블록은 fetchDataFromServer()의 비동기 완료 여부와 상관없이 실행되므로, 로딩 상태가 너무 일찍 false로 변경된다.

해결 방법

이 문제를 해결하려면, finally 블록 대신 .finally() 메서드를 사용해야 한다.

function downloadFile() {
  setLoading(true);
  fetchDataFromServer()
    .then((response) => response.blob())
    .then((blob) => {
      const url = createDownloadUrl(blob);
      triggerDownload(url, "output.pdf");
    })
    .catch(handleError)
    .finally(() => setLoading(false)); // 비동기 완료 후 실행
}

또한, async/await을 사용하여 보다 가독성이 좋은 방식으로 작성할 수도 있다.

async function exportPDF() {
  setLoading(true); // 로딩 시작
  try {
    const response = await fetchDataFromServer();
    const blob = await response.blob();
    const url = createDownloadUrl(blob);
    triggerDownload(url, "output.pdf");
  } catch (error) {
    logError("Download failed", error);
  } finally {
    setLoading(false); // 로딩 종료
  }
}

두 함수는 같은 기능을 수행하지만, then/catch 방식과 async/await 방식을 각각 활용하여 다른 형태로 구현할 수 있다. 상황에 따라 적절한 방식을 선택하는 것이 중요하다.

결론

  • try...catch...finally는 동기 코드에서는 정상적으로 작동하지만, 내부의 비동기 코드가 완료되기 전에 finally가 실행될 수 있다.
  • 비동기 작업이 끝난 후 특정 작업을 실행하려면 .finally()를 사용해야 한다.
  • async/await을 활용하면 더 명확한 흐름을 만들 수 있다.
  • try...catch...finally는 비동기 작업의 성공/실패 여부와 무관하게 항상 실행되지만, 프로미스 체인을 기다리지 않는다.
  • 같은 기능을 수행하는 코드라도 then/catch와 async/await의 형태로 다르게 표현할 수 있다.

이러한 동작을 이해하고 코드를 작성하면, 비동기 흐름을 더욱 효과적으로 관리할 수 있다.

반응형

'개발공부 > Javascript' 카테고리의 다른 글

ECMAScript 6  (0) 2021.12.28
DOM 이란?  (0) 2021.12.28
Javascript Pattern  (0) 2021.12.28
번들링(Bundling)  (0) 2021.12.28
Comments