Javascript
try catch문에 finally가 필요한 이유
tea-tea
2024. 11. 29. 14:19
finally 블록은 try catch 문의 실행 이후 무조건 실행되므로 리소스 해제 등의 작업에 적합하다.
그런데, 굳이 finally를 쓰지 않고 아래처럼 try catch 뒤에 실행될 코드를 적으면 되는거 아닐까.
function init() {
try {
throw new Error("에러1");
} catch (err) {
console.error(err);
}
console.log("후속 작업");
}
init();
아니다. finally만의 고유 기능 때문에 사용해야 하는 경우가 있다.
1. catch문에서 에러가 날 경우, 일반 코드는 실행되지 않지만, finally 문은 실행된다.
finally를 사용하는 경우
function useFinally() {
try {
throw new Error("에러1");
} catch (err) {
throw new Error("에러2");
}
// catch문에서 에러가 나도 무조건 실행이 됨
finally {
console.log("후속 작업");
}
}
useFinally();
finally를 사용하지 않는 경우
function notUseFinally() {
try {
throw new Error("에러1");
} catch (err) {
throw new Error("에러2");
}
// catch 문에서 에러가 나면 실행되지 않음
console.log("후속 작업");
}
notUseFinally();
2. try문이나 catch 문에서 early return으로 함수를 조기 종료해도 finally는 실행된다.
finally를 사용하는 경우
function useFinally() {
try {
return "try 반환값";
} catch (err) {
console.error(err);
} finally {
console.log("후속 코드 실행");
}
}
console.log(useFinally());
// 콘솔 출력 결과
// "후속 코드 실행"
// "try 반환값"
finally를 사용하지 않는 경우
function notUseFinally() {
try {
return "try 반환값";
} catch (err) {
console.error(err);
}
console.log("후속 코드 실행");
}
console.log(notUseFinally());
// 콘솔 출력 결과
// "try 반환값"
주의사항. finally의 반환 값 혹은 예외는 기존 반환 값을 덮어쓴다.
표면 상으로는 finally가 먼저 실행된 후 early return이 실행되는 것 처럼 보이지만,
실제로는 early return문이 먼저 실행되되, 이것이 반환 값으로 예약되고, 이후 finally가 완료된 후에 호출자 함수로 반환이 이뤄진다. (즉, return => 리턴 값 예약 => finally {} => 호출자 함수로 리턴 값 및 제어권 반환 순서이다)
여기서 더 주의할 건, finally의 return문이나 throw문은 try나 catch의 반환값 혹은 던진 예외를 덮어쓸 수 있다
아래 경우에서는 모두 finally 반환 값이 다른 조기 반환값이나 예외를 덮어쓴다.
try에서 리턴하는 경우
function useFinally() {
try {
return "try 반환값";
} catch (err) {
console.error(err);
} finally {
return "finally 반환값";
}
}
console.log(useFinally());
catch에서 에러를 던지는 경우
function useFinally() {
try {
throw new Error("에러1");
} catch (err) {
console.error(err);
} finally {
return "finally 반환값";
}
}
console.log(useFinally());
단, try catch 블록보다 먼저 실행된 조기 반환은 애초에 try catch 블록이 실행조차 안되었으므로, 조기 반환 값이 최종적으로 반환된다.
function useFinally() {
return "일반 반환";
try {
throw new Error("에러1");
} catch (err) {
console.error(err);
throw new Error("에러1");
} finally {
return "finally 반환값";
}
}
console.log(useFinally());