자바스크립트의 에러와 처리 방법에 대해서 알아보기 (js-error)
May 8, 2020 9:00 AM:javascript, nodejs, es6
최근 취업 준비를 위해 포트폴리오를 작성하고 있다. 그 포트폴리오에 들어갈 만한 프로젝트를 진행하던 도중 서버와 클라이언트가 통신하는 과정에서 오류에 대한 처리를 할 때 오류에 대한 지식이 별로 없다보니 처리가 힘들었다. 에러란 뭔지 어떻게 처리해야 하는지 등에 대해서 정리해본다.
런타임 시에 발생하는 오류에 대한 객체다. 런타임시에 발생하는 오류에 대해 적절하게 예외 처리를 하고 핸들링 할 수 있어야 우리가 작성한 애플리케이션이 정상적으로 동작할 수 있다. 에러 객체는 사람이 읽을 수 있는 에러에 대한 설명과 어떤 부분에 오류가 났는지에 대한 설명, 에러 객체 자신에 대한 이름 등을 담고 있다.
주로 최신 스펙으로 만들어진 자바스크립트 엔진에서는 async/await
를 사용하는 함수 내에서 try...catch
와 주로 쓰인다.
async function something(someValue) {
try {
const { data } = await axios.get('/api/list/' + someValue)
} catch (error) {
throw new Error(error)
}
}
something(1)
axios
라는 라이브러리를 사용해 서버와 통신한다. 오류가 발생할 경우 throw
구문을 사용해 예외 값을 이 함수를 호출한 곳으로 던진다. 이렇듯 일반적인 상황에서 이렇게 사용할 수 있다. 서버에서 받은 값을 기반으로 특정한 에러를 던지거나 해야할 때는 아래와 같이 사용할 수 있다.
async function something(someValue) {
try {
const { data } = await axios.get('/api/list/' + someValue)
if (data.isMistake) {
throw new Error('something wrong')
}
} catch (error) {
errorHandling(error)
}
}
something(1)
에러 객체는 자신의 이름과 사람이 읽을 수 있는 에러에 대한 설명을 담고 있는 메세지 프로퍼티로 구성되어 있는데 각각 에러 객체의 name
과 message
속성에 접근해 얻을 수 있다.
일반적인 Error 객체 외에 자바스크립트에서 미리 만들어진 에러 객체가 몇 개 존재한다. 그 중에서 몇 가지는 매우 많이 봐왔던 에러다.
기본적으로 존재하는 Error 객체를 포함해 총 8개의 에러 객체가 있다. 이 중 ReferenceError와 TypeError는 수도 세지 못할 만큼 본 것 같다.
그렇다면, 나만의 커스텀 에러 객체를 만들 수 없을까? 당연히 만들 수 있다! ES6 이후 스펙의 자바스크립트 코드를 이용하면 매우 쉽게 이용할 수 있지만 최신 스펙을 사용할 수 없는 환경도 존재하기 때문에 각각 따로 나눠 사용해본다.
ES6 이전의 자바스크립트에서 커스텀 에러 객체를 만든다.
function CustomError(message) {
this.message = message
// 이 부분은 new Error().stack 과 동일하다.
this.stack = Error().stack
}
CustomError.prototype = Object.create(Error.prototype)
CustomError.prototype.name = 'CustomError'
// throw 구문은 모든 브라우저에서 사용할 수 있는 구문이다.
throw new CustomError('Emit CustomError')
커스텀 에러 객체를 만들어내는 생성자 함수를 만들어서 프로토타입을 조작해주면 자신만의 에러 객체를 만들 수 있다. 이 말은 기본적으로 자바스크립트에서 제공하는 에러 객체를 확장시킬 수 있고 다채로운 에러 처리를 할 수 있게 된다는 말이다.
ES6 이후에는 Error 객체를 상속받는 클래스를 지정해서 보다 간결하고 쉽게 만들 수 있다.
class CustomError extends Error {
constructor(message) {
super(message)
this.name = 'CustomError'
}
toString() {
return this.name + ': ' + this.message
}
}
throw new CustomError('Emit CustomError')
위의 ES6 이전의 코드에 비해 매우 간결해졌다. 메소드를 오버라이딩해서 다르게 보이게 할 수도 있고 좀 더 다양한 처리가 가능해졌다. 그리고 이러한 것도 가능하다.
class CustomError extends Error {
constructor(message) {
super(message)
this.name = 'CustomError'
}
toString() {
return this.name + ': ' + this.message
}
}
class MyError extends Error {
constructor(message) {
super(message)
this.name = 'MyError'
}
toString() {
return this.name + ': ' + this.message
}
}
function start() {
throw new MyError('1')
// throw new CustomError('2')
}
try {
start()
} catch (e) {
if (e instanceof MyError) {
console.log('catch MyError')
} else if (e instanceof CustomError) {
console.log('catch CustomError')
}
}
서로 다른 에러 객체 두 개와 무조건 에러를 던지는 함수 하나를 만들어 try...catch
블록에서 던져지는 에러의 타입을 비교해서 다양한 처리를 할 수 있다. (start 함수에 주석을 하나씩 넣고 제거해서 테스트 하기)