에러 발생과 예외 처리

작성한 코드를 실행하다보면 필연적으로 에러가 발생하게 됩니다.

에러가 발생하면 코드의 실행이 멈추고 에러메시지가 콘솔에 표시됩니다.

에러가 발생하는 원인은 여러가지가 있습니다. 

친절하게 에러메시지로 원인을 알려주는 오타나 코드 오류같은 단순 오류들 부터, 원인을 알 수 없는 모호하거나 심각한 에러들까지 다양합니다.

어떤 경우에는 에러메시지 없이 코드 실행이 중단되거나, 웹브라우저가 멈추기도 합니다.

주로 메모리 누수나, 파일 처리등 시스템과 관련된 처리를 할 때 많이 발생합니다.

이런 심각한 오류들은 적당한 오류 메시지를 내보내고 정상적으로 코드 실행을 종료 수 있도록 할 필요가 있습니다.

그래야 에러가 발생한 위치와 원인을 파악할 수 있기 때문입니다.

웹브라우저가 먹통이 되거나 파일이 잠겨서 다음번 코드 실행시에 접근이 안되는 문제가 생길 수 있기 때문에, 정상적으로 코드 실행이 종료되도록 하는 것은 중요합니다.

이런 오류 상황에 대응할 수 있도록 만들어진 기능이 예외 처리 입니다.

예외처리는 대부분의 개발 언어에서 제공되며, 사용방법과 문법도 거의 동일합니다.

다른 언어에서 예외 처리를 해본 경험이 있으면 자바스크립트에서도 같은 방법으로 예외처리를 할 수 있습니다.

자바스크립트의 예외를 처리하는 구문은 2가지입니다.

throw

에러 상황이라고 판단될 경우 강제로 예외 오류를 발생시키고 코드 실행을 종료하는 구문 입니다.

사용자가 코드상에 직접 원하는 위치에 예외 오류를 발생시키고 실행을 중지하는데 사용합니다.

에러 메시지를 구문과 함께 전달할 수 이습니다.

throw '사용자 지정 에러 메시지!';

이렇게 작성하면 해당 위치에서 코드 실행은 멈추게 되고, 예외 오류가 발생합니다.

function myFunc(param){    throw '사용자 정의 예외 발생!';    console.log(param + ' run!');}
myFunc('myFunc');

이렇게 예외 오류를 발생시키는 함수를 실행하면 예외 오류를 발생시킨 throw 구문에서 코드 실행은 멈추고 그 밑의 콘솔 로그 출력은 실행 되지 않습니다.

try~catch~finally

에러가 발생할 수 있는 코드 블록을 감싸서, 에러가 발생할 경우 catch 블록에서 발생한 에러에 대한 대응을 할 수 있도록 합니다.

그리고 예외 발생 여부와는 무관하게 무조건 실행되도록 하는 코드를 finally 블록에 추가할 수 있습니다.

예를 들어 파일을 읽어서 처리하는 코드 블록을 try 블록에 넣어서 실행하다 에러가 발생하면 catch 블록으로 실행 제어가 넘어갑니다.

catch 블록에서는 에러 내용을 출력합니다.

catch 블록은 파라메터로 Exception 객체를 넘겨받게 되며, Exception 객체의 에러 메시지 내용을 담은 message 속성을 통해 에러의 원인을 알아낼 수 있습니다.

try 블록에서 처리가 정상 완료되었거나, catch 블록에서 에러 처리를 한 후에는 finally 블록에 넣은 파일을 닫는 코드가 무조건 실행됩니다.

가상코드로 try~catch~finally 코드 구조를 짜면 아래와 같습니다.

let fo = openFile();

try{

fo.readFile();

}catch(ex){

console.log(ex.message); // 또는 Exception 상세 내용을 보려면 console.log(ex); 로 Exception 객체 전체를 출력할 수도 있습니다.

}finally{

if(fo){ // 파일 객체가 존재하는지 먼저 체크

fo.close();

}

}

읽기/쓰기 위해서 연 파일은 반드시 닫아야 합니다. 

닫지 않고 코드를 종료할 경우 파일이 열린 상태이기 때문에 파일이 잠겨서(lock) 다음번 실행할 때 파일을 읽을 수 없게 됩니다.

이런 문제를 미연에 방지하기 위해, 무조건 실행되는 finally 블록에 파일을 닫는 코드를 넣어 코드의 안정성을 끌어올릴 수 있습니다.

실제로 예외 처리를 하지 않은 코드 블록으로 파일을 읽다보면 파일이 잠겨서 웹브라우저를 강제 종료해야하는 경우가 종종 발생합니다.

무조건 실행되는 코드 블록이 필요하지 않은 경우 finally 블록은 생략할 수 있습니다.

간단하게 에러를 발생시켜 try~catch~finally 가 어떤 식으로 동작하는지 웹브라우저에서 확인해봅니다.

const a = 0;
try{    console.log(b); //b가 정의되지 않아서 에러를 발생함.}catch(error){    console.log(error.message); // b is not defined 메시지를 콘솔에 출력}finally{    console.log(a); // a의 값을 무조건 출력함}

입력 필드에서 선택한 텍스트 파일을 읽어 콘솔에 출력하는 처리를 try~catch~finally 로 예외 처리를 구현하면 다음과 같이 구현할 수 있습니다.

let data;let fname = document.getElementById('selectfile');try {    var reader = new FileReader();    reader.addEventListener('load', function () {        data = reader.result;        console.log('파일 내용 : '+reader.result);    });    reader.addEventListener('error', function () {        throw '파일 읽기 에러'    });    reader.readAsText(fname.files[0], "utf-8");} catch (err) {    console.log(err.message);} finally {    console.log('파일 읽기 종료');}

파일이 없을 경우 '파일 읽기 에러' 메시지로 throw를 발생시키고 catch 블록에서 해당 예외 처리 메시지(Uncaught 파일 읽기 에러)를 출력하고 종료합니다.