Frontend 개발자 - hyo.loui
모던 Javascript - 에러 처리 본문
❤️🔥TIL : Today I Learned
에러 처리
에러 처리의 필요성
에러는 언제나 발생할 수 있다.
발생한 에러에 대해 대처하지 않고 방치하면 프로그램은 강제 종료된다.
에러 처리의 필요성
console.log('[Start]');
foo(); // ReferceError : foo is not defined
// 발생한 에러를 방치하면 프로그램은 강제 종료된다.
console.log('[End]');
위 예시 코드에서 [End] 가 출력되지 않는다.
이러한 현상이 프로젝트에서 발생한다면... 끔찍하다.
- try...catch
console.log('[Start]');
try {
foo();
} catch (error) {
console.log('[에러 발생]', error);
// [에러 발생] ReferenceError : foo is not defined
}
console.log('[End]');
- 옵셔널 체이닝 (?.)
const $button = document.querySelector('button'); // null
$button.classList.add('disabled');
// TypeError: Cannot read property 'classList' of null.
$button?.classList.add('disabled');
이처럼 에러나 예외적인 상황에 대응하지 않으면 프로그램은 강제 종료된다.
try...catch...finally 문
- 기본적으로 에러 처리 구현방법은 크게 두 가지가 있다.
- if 문이나 단축평가 또는 옵셔널 체이닝 연산자를 통한 방법.
- 에러 처리 코드를 미리 등록해 에러 발생시 처리 코드로 점프 하도록 하는 방법.
여기서 알아볼 try...catch...finally 문은 두 번째 방법이다.
* 일반적으로 이 방법을 에러 처리(error handling) 라고 한다.
console.log('[Start]');
try {
// 에러가 발생할 가능성이 있는 코드
foo();
} catch (err) {
// try 코드 블록에서 발생한 Error 객체가 전달된다.
console.error(err);
} finally {
// 에러 발생과 상관없이 반드시 한 번 실행된다.
console.log('finally');
}
console.log('[End]');
Error 객체
- Error 생성자 함수는 에러 객체를 생성한다.
- 에러를 상세히 설명하는 에러 메세지를 인수로 전달할 수 있다.
에러 객체의
message 프로퍼티의 값은 Error 생성자 함수에 인수로 전달한 에러 메시지 이고,
stack 프로퍼티의 값은 에러를 발생시킨 콜스택의 호출 정보를 나타내는 문자열이며 디버깅 목적으로 사용한다.
1 @ 1; // SyntaxError: Invalid or unexpected token
foo(); // ReferenceError: foo is not defined
null.foo(); // TypeError: Cannot read property 'foo' of null
new Array(-1); // RageError: Invalid array length
decodeURIComponent('%'); // URIError: URI malformed
throw 문
Error 생성자 함수로 에러 객체를 생성한다고 에러가 발생하는 것은 아니다.
즉, 에러 객체 생성과 에러 발생은 의미가 다르다.
const repeat = (n, f) => {
// 매개변수 f에 전달된 인수가 함수가 아니면 TypeError를 발생시킨다.
if (typeof f !== 'function') throw new TypeError('f must be a function');
for (let i = 0; i < n; i++) {
f(i)
}
};
try {
repeat(2, 1);
} catch (err) {
console.error(err);
}
위 코드의 흐름은
n 만큼 function을 반복하는 함수를 생성했다.
repeat 함수는 에러를 발생시킬 가능성이 있으므로 try 코드 블록 내부에서 호출해야 한다.
또한 repeat 함수에서는 if 문으로 함수가 아닌 경우에 throw 하고 함수는 에러 객체를 생성한 후 종료 된다.
객체는 catch 문의 인수로 전달되어 console.error에 도달한다.
이후 나머지 코드로 진행된다.
에러의 전파
const foo = () => {
throw Error('foo에서 발생한 에러'); // 4
console.log("여기 실행 안됨")
};
const bar = () => {
foo(); // 3
console.log("여기 실행 안됨")
};
const baz = () => {
bar(); // 2
console.log("여기 실행 안됨")
};
try {
baz(); // 1
console.log("여기 실행 안됨")
} catch (err) {
console.error(err)
}
이렇게 foo 함수가 throw 한 에러는 다음과 같이 함수를 호출한
호출자에게 전파되어 전역에서 캐치된다.
- 주의할 것은 비동기 함수에서는 호출자가 없다는 것 이다. 비동기 함수는 테스크 큐나 마이크로테스크 큐에 일시 저장되었다가 콜 스택이 비면 이벤트 루프에 의해 콜 스택으로 푸시되어 실행된다. 이 때 콜 스택에 푸시된 콜백 함수의 실행 컨텍스트는 콜 스택의 가장 하부에 존재하게 된다. 따라서 에러를 전파할 호출자가 존재하지 않는다.
최종 정리
- 에러는 언제나 발생할 수 있다. 발생한 에러에 대해 대처하지 않고 방치하면 프로그램은 강제 종료 되므로 에러 처리가 필요하다.
- 에러 처리 방법에는 크게 두가지 이다.
- if 문이나 단축평가 또는 옵셔널 체이닝 연산자를 통한 방법.
- 에러 처리 코드를 미리 등록해 에러 발생시 처리 코드로 점프 하도록 하는 방법. (try...catch)
- Error 생성자 함수는 에러 객체를 만드는 것이므로 throw 해서 error객체를 catch의 인수로 전달해야 한다.
- 에러는 호출자를 타고 전파된다. 하지만 비동기 함수는 호출자가 없기 때문에 주의해야 한다.
'Javascript' 카테고리의 다른 글
.require과 import의 차이점 / 배열 또는 객체를 const로 선언 후 요소나 속성을 추가할 수 있는 이유 (0) | 2023.04.03 |
---|---|
모던 Javascript - 모듈 (0) | 2023.04.01 |
this (0) | 2023.03.31 |
모던 Javascript - Ajax (0) | 2023.03.30 |
모던 Javascript - DOM (0) | 2023.03.30 |