프로그래밍에서 다양한 이유로 에러가 발생하게되는데, 에러가 발생하게 되면 스크립트(쉽게 생각하면 프로그램을 구성하는 코드)는 중단되고 에러가 출력되게된다.
이런 상황을 유저가 겪게된다면 작업한 모든 내용을 잃을 수도 있게되고 다시는 프로그램을 사용하지 않게될 수 도있다.
이런 상황을 대처하기 위해서 자바스크립트에서는 try...catch를 이용해 예외(에러)가 발생했을때 후속처리를 통해 스크립트를 살리고 프로그램이 안정적으로 실행될 수 있도록 해준다.
try {
//예외(에러)가 발생할 수 있는 코드
} catch (error) {
//예외(에러)가 발생했을때 처리하는 코드
}
실행흐름은 다음과 같다.
catch(error) { ... }의 변수명은 마음대로 정할 수 있다.
catch(e) { ... }, catch(err) { ... } 등등
try {
console.log("코드 시작"); // 코드 시작
} catch (e){
console.log("에러 발생"); // 에러가 발생하지 않아 실행되지 않음
}
try {
console.log("코드 시작"); // 코드 시작
abcd(); //선언하지 않은 함수 실행으로 에러 발생, 코드실행이 중지되고 catch로 제어권이 넘어감
console.log("코드 끝"); // 이 코드는 실행되지 않음
} catch (e){
console.log("에러 발생"); // 에러 발생
}
위 코드처럼 에러가 발생하더라도 예외처리를 통해 프로그램이 강제로 종료되지 않고 적절한 조치를 취할 수 있게된다.
try {
console.log("1"); // 1
setTimeout(function() {
console.log("2"); // 1과 3 출력 후 1초 뒤에 2가 출력
abcd(); // 선언하지 않은 함수 실행 에러 발생
console.log("코드 끝"); // 실행되지 않음
}, 1000);
console.log("3"); // 3
} catch (e) {
console.log("에러 발생"); // 해당 코드는 실행되지 않음
}
방법은 간단하다. 비동기적인 함수내에 다시 try...catch를 이용해 예외처리를 해주면 된다.
try {
console.log("1"); // 1
setTimeout(function() {
try {
// 비동기 작업, 예외가 발생할 수 있는 작업
console.log("2"); // 2
abcd(); // 함수가 정의되어 있지 않음 에러 발생
console.log("코드 끝"); // 실행되지않음
} catch (error) {
console.log("비동기 코드 내에서 에러 발생"); // 비동기 코드 내에서 에러 발생
}
}, 1000);
console.log("3"); // 3
} catch (e) {
console.log("에러 발생"); // 해당 코드는 실행되지 않음
}
try...catch는 에러가 발생하게 되면 에러의 내용이 담긴 객체를 생성한 뒤 catch(e)의 인수로 전달해준다.
일반적으로 이런 예외가 발생했을 때 전달받은 에러 객체에는 몇가지 기본 프로퍼티가 제공되는데 다음과 같다.
try {
console.log("코드 시작"); // 코드 시작
abcd(); // 에러 발생, catch로 에러 객체와 함께 제어권이 넘어감
console.log("코드 끝") // 실행되지 않음
} catch (e) {
console.log("에러 발생"); // 에러 발생
console.log(e); //e: ReferenceError: abcd is not defined
console.log("name: " + e.name); // name: ReferenceError
console.log("message: " + e.message); // message: abcd is not defined
console.log("stack: " + e.stack);
// stack: ReferenceError: abcd is not defined
// at neyozodate.js:4:3
// at https://static.jsbin.com/js/prod/runner-4.1.8.min.js:1:13924
// at https://static.jsbin.com/js/prod/runner-4.1.8.min.js:1:10866
}
try...catch문에서 에러가 발생하면 catch로 제어권이 넘어감과 동시에 에러 객체를 전달해준다는걸 알았다. 그럼 이걸 이용해서 에러가 발생했을때 핸들링 하는걸 알아보자.
throw "Error"; // 문자열 "Error"를 갖는 예외 발생
throw 20; // 20값을 갖는 예외 발생
throw true; / true값을 갖는 예외 발생
이 처럼 throw 이후 값을 적어주면 해당 예외가 발생하지만 이런식으로 예외가 발생하면 무엇을 의미하는지 알수 가 없기 때문에 자바스크립트의 표준 에러 객체 관련 생성자를 이용해 에러 객체를 만든다.
let error = new Error(message);
'' = new SyntaxError(message);
'' = new ReferenceError(message);
Error, SyntaxError, ReferenceError 등과 new를 이용해 에러 객체를 생성한다.
try {
const num = 2;
if(num % 2 === 0){
throw new Error("짝수 에러를 발생시킵니다.")
}
console.log("코드 끝"); // 실행되지 않음
} catch (error){
console.log(error.name); // "Error"
console.log(error.message); // "짝수는 에러를 발생시킵니다."
에러 객체 관련 생성자를 이용해 에러 객체를 만든다면 name은 생성자의 이름 message는 인수값이 된다. 위 코드에서는
throw new Error("짝수 에러를 발생시킵니다.") 중에서
어떤 에러가 발생할지 모두 예측하고 처리해주면 좋겠지만 사실 거의 불가능하다고 봐야한다. catch에서는 알고 있는 에러만 처리하고 나머지는 다시 에러를 던져줘야 한다.
function readData(){
let json = '{ "age": 30 }'; // 불완전한 데이터
try {
let user = JSON.parse(json);
if (!user.age) {
throw new SyntaxError("불완전한 데이터: 나이없음");
}
abcd(); // 예상치 못한 에러
alert( user.age ); //실행되지않음
} catch(e) {
if (e instanceof SyntaxError) {
alert( "JSON Error: " + e.message ); // 이 코드는 ReferenceError에러이다. 때문에 실행되지 않음
} else {
console.log(e.name) // ReferenceError
throw e; // 에러 다시 던지기
}
}
}
try{
readData();
} catch(e){
alert("에러 다시 잡기"); //alery로 "에러 다시 잡기"가 뜸
}
위 코드에서는 나이가 없는 json 데이터가 들어오면 SyntaxError에러를 발생시키고 해당 함수 내에서 처리를 한다. 그외에 알 수 없는 에러는 다시한번 throw를 하게 된다.
위 코드를 실행하면 alert창으로 "에러 다시 잡기" 가 뜨게 된다.
이런 식으로 처리할 수 있는 에러만 처리한 뒤 모르는 에러는 다시 던져야 스크립트가 죽는 것을 최소한으로 줄일 수 있게 된다.
try...catch는 finally 라는 코드를 하나 더 사용 할 수 있다.
finally 코드는 다음와 같은 경우 실행된다.
이 두 경우 finally가 실행되고 코드는 종료 된다.
에러가 없는 코드
try{
console.log("코드 시작"); // 코드 시작 (1)
} catch(e){
console.log("에러 발생") // 실행되지 않음
} finally{
console.log("finally 실행") // finally 실행 (2)
}
에러가 있는 코드
try{
console.log("코드 시작"); // 코드 시작 (1)
abcd(); // 에러 발생 제어권이 catch로 넘어감
console.log("코드 끝"); // 실행되지않음
} catch(e){
console.log("에러 발생") // 에러 발생 (2)
} finally{
console.log("finally 실행") // finally 실행 (3)
}
finally는 return을 사용해 빠져 나가더라도 실행된다. 또한 return이 반환되기 전에 finally가 실행된다.
function testData(){
try{
alert("코드 시작"); // 코드 시작 (1)
return "20리턴";
} catch(e){
console.log("에러 발생") // 실행되지않음
} finally{
alert("finally 실행"); // finally 실행 (2)
}
}
alert( testData() ); // 20리턴 (3)
try {
// 예외가 발생할 수 있는 코드
} catch {
// 예외를 처리하는 코드 (e)없이 작성
console.log("예외를 처리했습니다.");
}