예외처리란?
- 예외는 간단하게 말해 오류가 난 상황을 얘기합니다.
- 일반적으로 프로그램에 오류가 발생하면 해당 프로그램은 강제적으로 종료됩니다. 하지만 자바스크립트 프로그램에서 발생한 오류는 굳이 프로그램을 종료하지 않더라도 오류만 적절하게 처리해준다면 프로그램을 계속 실행시킬 수 있습니다.
더 자세히
- 프로그램을 실행하면서 예상치 못한 오류가 발생할 수도 있고, 오류는 아니지만 특별한 대처가 필요한 예외적인 상황이 생길 수 도 있습니다.
예를 들어 파일이 존재하지 않거나 함수에 주어진 인수가 그 함수가 사용하려는 데이터 타입이 아닌 경우 등이 있습니다. 이 때 함수는 일반적으로 null 값을 반환해 오류를 알리는 방법을 사용하지만, 또 다른 방법으로 예외(Excepttion)를 던지는(Catch) 방법이 있습니다.
예외를 던져서 오류 또는 예외 조건이 발생했다는 사실을 통지하고, 통지를 받은 쪽은 예외를 받아서 적절한 처리를 해주게 됩니다. - 예외를 받아서 처리하는 부분을 가리켜 예외 처리기라고 하고, 예외를 받는 작업을 가리켜 예외를 잡는다 (catch 한다) 라고 합니다.
- JavaScript 에서는
throw
문으로 예외를 던지고try/catch/finally
문으로 예외를 잡아서 처리하게 됩니다.
JavaScript 에서의 예외처리
throw 문
throw 문에서는 예외를 던집니다.
throw 표현식;
표현식으로는 어떠한 타입의 값도 지정할 수 있습니다.
사용자에게 표시할 오류 메시지가 포함된 문자열이나 오류 코드를 의미하는 숫자도 허용됩니다. 하지만 일반적으로 Error 객체나 Error 객체를 상속받은 객체를 지정합니다.
예시
function permutation(a) { if( !(a instanceof Array) ){ throw new Error(a+"is not an Array"); } } permutation("ABC"); // Error: ABC is not an Array
예외를 던지면 자바스크립트 인터프리터가 프로그램의 실행을 중단하고 바깥 블록에서 예외를 처리하는 예외 처리기를 찾습니다.
예외 처리기는 바로try/catch/finally
절 부분의 catch 문을 의미합니다. 예외처리기가 없으면 프로그램을 그냥 종료합니다.
Error 객체
자바스크립트에는 예외를 표현하기 위한 내장 객체 7가지가 있습니다.
예외를 표현하는 내장객체의 생성자
생성자 | 생성하는 인스턴스 |
---|---|
Error | 범용적인 예외 객체 |
EvalError | eval 함수와 관련해서 발생한 예외 객체 |
RangeError | 숫자 값이 허용 범위를 벗어났을 때 발생하는 예외 객체 |
ReferenceError | 잘못된 참조를 만났을 때 발생하는 예외 객체 |
SyntaxError | 자바스크립트 문법에 맞지 않는 구문을 만났을 때 발생하는 예외 객체 |
TypeError | 변수 및 인수의 타입이 유효하지 않을 때 발생하는 예외 객체 |
URIError | encodeURI와 decodeURI 메서드에 잘못된 인수가 전달되었을 때 발생하는 예외 객체 |
- 예외를 표현하는 모든 내장 객체는 Error.prototype의 프로퍼티와 메서드를 상속받습니다.
- Error.prototype의 프로퍼티
- message : 오류 메시지를 의미하는 문자열
- name : 오류의 이름
- toString : 지정된 객체를 표현하는 문자열을 반환
try/catch/finally 문
예외가 던져졌을 때 그것을 잡아서 처리하는 부분입니다.
try{ // 실행할 코드 ( 예외가 발생할 수 있는 코드 ) } catch(exception){ // try 블록에서 예외가 발생했을 때 실행되는 코드 // exception에는 예외 값이 들어와 이 값을 바탕으로 예외를 처리 } finally{ // try 블록 코드와 catch 블록 코드가 실행된 이후에 반드시 실행됨 }
finally 블록 안의 코드는 예외 처리에 마지막에 반드시 실행됩니다.
try 블록이나 catch 블록에서 return, continue, break 문을 만나더라도 반드시 finally 블록 안의 코드가 실행이 됩니다.
예외가 여러 개 발생했을 때의 대처
instanceof 연산자 이용
try{ // try 블록에서 오류가 발생한다 } catch(e){ if( e instanceof TypeError ){ // TypeError가 발생했을 때의 처리 코드 작성 }else if( e instanceof ReferenceError ) { // ReferenceError 가 발생했을 때의 처리 코드 작성 }else{ // 나머지 경우의 에러가 발생했을 때의 처리 코드 작성 } }
비동기 처리의 콜백 함수가 던진 예외의 처리
- 비동기 처리의 콜백함수가 던진 예외는 콜백함수를 넘긴 함수로 전파되지 않습니다.
try {
setTimeout(function throwError(){
throw new Error("오류가 발생했습니다");
},1000);
} catch(e){
console.log("예외 캐치 ->" + e);
}
위 코드의 실행 결과는Uncaught Error: 오류가 발생했습니다
라는 내용이 표시되고 예외가 캐치되지 않은 상태로 프로그램이 종료됩니다.
예외를 던지는 콜백함수 throwError 는 함수 정의가 try 블록 안에 있을 뿐 try 블록 안에서 호출된 것은 아닙니다. 이 콜백 함수를 호출한 주체는 타이머 이벤트이며 try 블록 안에서 발생한 예외가 아닙니다. 그래서 예외를 잡을 수 없습니다.
이렇게 비동기 처리의 콜백 함수에서 발생한 예외는 바깥의 try/catch 문으로는 잡을 수 없습니다.
ES6 부터 추가된 제너레이터를 활용하면 이러한 비동기 처리 중 발생한 예외를 잡을 수 있습니다.
- 아래 함수 run 은 인수로 받은 함수 callback을 실행시킵니다. 이때 인수로 받은 함수가 비동기 처리를 하는 중에 발생시킨 예외도 잡아서 처리합니다.
- 두 번째 이후 인수로 callback 함수가 원래 받아야 하는 모든 인수를 지정할 수 있습니다. callback 함수는 첫 번째 인수로 제너레이터의 참조인 g를 받아야 합니다. 그리고 callback 함수 안에서 예외를 던질 때 g.throw 메서드를 실행합니다.
// function test
function sleepAndError(g,n){
setTimeout(function(){
for(var i=0; i<n; i++) console.log(i); // do something
g.throw(new Error("오류가 발생했습니다"));
}, 1000);
}
// callback 함수를 실행하는 함수 : callback 함수가 비동기 처리 중에 발생시킨 예외도 잡아서 처리함
function run(callback, ...argsList){
var g = (function* (cb,args) {
try{
yield cb(g, ...args);
} catch(e){
console.log("예외를 잡음 -> " + e);
}
})(callback, argsList);
g.next();
}
// 실행
run(sleepAndError, 10);
- 실행결과
0 1 2 ... 예외를 잡음 -> Error : 오류가 발생했습니다.
- sleepAndError 함수의 실행을 run 함수에 위임합니다. sleepAndError 함수는 setTimeout 함수를 사용해서 약 1초 후에 예외를 던지는 비동기 처리를 하는 함수입니다. sleepAndError 함수가 예외를 던질 때 그 예외를 throw문이 아니라 첫 번째 인수로 받은 제너레이터 객체 g의 throw 메서드에 던지는 부분이 포인트입니다. 제너레이터 객체 g 의 throw 메서드는 호출된 그 자리에서 예외를 던지는 것이 아니라 제너레이터를 한 번 동작 시킨 다음에 yield문이 위치한 자리에서 예외를 던집니다. 그러면 이 예외는 제너레이터가 던진 예외가 되므로 catch 블록 안에서 잡아낼 수 있습니다.
반복문에서 빠져나오기
- 중첩 반복문처럼 깊은 반복문 안에서 탈출할 때에도 예외 매커니즘을 사용할 수 있습니다.
- 예시로 forEach 문은 실행하는 도중에 취소할 수 없지만 예외 매커니즘을 이용하면 실행 중인 반복문에서 빠져나올 수 있습니다.
var a = [0,1,2,3,4,5,6,7,8,9];
try{
a.forEach(function(v,i,a){
if(i>5){
throw false;
}
return a[i] = v*v;
});
}catch(e){
if(e) throw e;
}
console.log(a); // -> [0,1,2,3,4,5,6,7,8,9]
- 의도하지 않은 예외가 try 블록 안에서 발생하는 경우를 대비하여 예외 값이 true로 평가되었을 때는 그 예외를 밖으로 던집니다. 예외 값이 false면 그 다음 코드인 console.log를 실행하게 됩니다.
참고도서 : 모던 자바스크립트 입문
'Study > JavaScript' 카테고리의 다른 글
JavaScript ) 다차원 배열 생성 (0) | 2022.01.27 |
---|---|
JavaScript ) 배열 기초 (0) | 2022.01.14 |
JavaScript ) 버그 잡아내기 (0) | 2022.01.07 |
JavaScript ) 자주 사용되는 정규식 (0) | 2022.01.07 |
JavaScript) 단축평가 (1) (0) | 2022.01.06 |
댓글