HOWTO · JavaScript

JavaScript에서 catch가 없는 Try

오늘 포스트에서는 자바스크립트에서 catch를 구현하지 않고 try 문에 대해 알아보겠습니다.

이 페이지의 내용

예 — JavaScript try 문은 finally 절이 있으면 catch를 생략할 수 있습니다. 이 튜토리얼에서는 catch 없는 try가 유효한 경우, throw된 오류에 어떤 일이 일어나는지, 그리고 이 형태가 적합한 도구인 경우를 설명합니다.

JavaScript에서 catch 없이 try가 작동하는 방식

JavaScript try 문은 오류를 throw할 수 있는 코드를 감싸며, 문이 허용되는 곳이라면 어디에서나 사용할 수 있습니다: 스크립트의 최상위 수준, 함수 내부, 또는 다른 try 안에 중첩된 곳입니다. 할 수 없는 것은 단독으로 서는 것입니다 — try 블록 뒤에는 catch 절, finally 절, 또는 둘 다가 와야 하므로 둘 다 없는 try만으로는 구문 오류가 됩니다. 중괄호 {}는 문이 하나뿐이어도 항상 필요합니다.

구문:

아래 코드 블록의 주석과 식별자 레이블은 원문과 동일하게 영어로 유지됩니다.

try {
  // try_statements: code that may throw
} catch (exception_var) {
  // catch_statements: handle the thrown value
} finally {
  // finally_statements: always run afterward
}
  1. try_statements는 실행할 문들입니다.
  2. catch_statements는 try 블록에서 값이 throw될 때 실행되는 문들입니다.
  3. exception_var는 연관된 catch 블록에 대해 throw된 값을 담는 선택적 식별자입니다.
  4. finally_statements는 값이 throw되거나 catch되었는지에 관계없이 try 문이 완료된 후 실행됩니다.

catch는 finally가 있을 때만 선택 사항이고(그 반대도 마찬가지입니다), 문법은 정확히 세 가지 조합을 허용합니다:

  1. try...catch
  2. try...finally
  3. try...catch...finally

catch 블록이 있고 try 블록 내부의 문(또는 그 문이 호출한 함수)이 throw하면 제어가 즉시 catch로 이동하고, 아무것도 throw되지 않으면 catch는 완전히 건너뜁니다. finally 블록은 값이 throw되었는지, catch가 그것을 처리했는지와 관계없이 try와 catch 블록이 끝난 뒤 항상 실행됩니다.

catch 절이 없으면 finally가 여전히 먼저 실행된 다음 throw된 값이 계속 호출자에게 전파됩니다. 이는 중첩에도 적용됩니다: try 문은 중첩될 수 있으며, 내부 try 문에 catch가 없으면 그것을 둘러싼 try의 catch 블록이 대신 오류를 처리합니다.

전체 문법은 MDN 문서의 try...catch를 참조하세요.

예제: catch 없는 try...finally

아래 스니펫은 자체 catch가 없는 try...finally를 바깥쪽 try...catch 안에 배치하여, finally 블록이 실행되는 모습과 throw된 값이 어디에 도착하는지 확인할 수 있게 합니다. 0 / 0은 NaN으로 평가되므로 throw new Error(0 / 0)은 메시지가 NaN인 Error를 throw합니다.

이 예제를 실행해 보세요:

아래 코드와 출력 블록에 표시되는 로그 레이블은 원문 예제와 동일하게 영어로 유지됩니다.

try {
  try {
    console.log('Executing try block')
    throw new Error(0 / 0)
  } finally {
    console.log('Final Call')
  }
} catch (error) {
  console.log('Outer catch received: ' + error.message)
}
Executing try block
Final Call
Outer catch received: NaN

내부 try는 로그 줄을 출력한 다음 throw합니다. catch가 없으므로 제어는 곧바로 finally로 이동하고, finally는 Final Call을 출력합니다. finally가 완료된 후에야 Error가 계속 전파되어 바깥쪽 catch가 이를 받아 NaN 메시지를 출력합니다. 둘러싸는 catch가 없었다면 같은 오류가 호출자에게 도달하거나, 최상위 수준에서는 Final Call이 출력된 뒤 처리되지 않은 오류로 나타났을 것입니다.

catch 없이 try를 사용하는 경우

블록에 보장된 정리(cleanup)가 필요하지만 오류 자체는 호출자의 몫일 때 try...finally를 사용하세요. 일반적인 finally 작업에는 리소스 해제, 연결이나 파일 핸들 닫기, 다시 활성화된 버튼이나 재설정된 플래그 같은 공유 상태 복원, 타이머 중지 등이 있습니다 — try 블록이 정상적으로 끝나든 throw하든 반드시 일어나야 하는 작업입니다.

코드가 오류에 추가할 의미 있는 내용이 없을 때 이 형태가 올바른 선택입니다: 오류를 그대로 다시 throw하는 것은 잡음을 더할 뿐이고, 빈 catch 블록은 모든 실패를 조용히 삼켜 버려 버그가 원인에서 멀리 떨어진 곳에서 드러나게 합니다. try...finally는 정리 보장을 유지하면서도 호출자가 오류를 보고 처리할 수 있게 해 줍니다. 함수가 throw된 값을 실제로 검사하거나, 로그에 남기거나, 복구해야 한다면 대신 실제 catch 절을 추가하세요.

catch 없는 try의 제한 사항과 함정

  • finally는 오류를 처리하거나 억제하지 않습니다. finally가 끝난 뒤에도 처리되지 않은 throw된 값은 계속 호출자에게 전파되며, 최상위 수준에서는 스크립트를 종료시키거나 처리되지 않은 오류를 보고합니다.
  • throw된 값을 관찰할 수 없습니다. catch가 없으면 이 구조는 무엇이 throw되었는지에 접근할 수 없으므로, 메시지를 로그하거나 오류 유형에 따라 분기할 수 없습니다.
  • finally 내부의 제어 흐름은 보류 중이던 것을 무엇이든 덮어씁니다. finally 안의 return이나 throw는 아직 전파 중인 값을 버립니다 — throw된 오류도 마찬가지로 조용히 사라집니다 — 따라서 finally는 return도 throw도 하지 않는 단순한 정리 작업으로 유지하세요.
  • try...finally 뒤에 오는 문들은 아무것도 throw되지 않았을 때만 실행되며, finally 자체도 실패 경로에서 실행되므로 try 블록이 성공했다는 전제에 의존해서는 안 됩니다.