자바스크립트 에서의 예외 처리
예외(Exception) - 예기치 못한 상황
다만, 예측하고 대비하면 프로그램을 멈출 필요가 없다. 자바에서의 try-catch-finally 와 동일한 개념이다.
아래의 코드를 보자.
try{
console.log("try 실행")
// 존재하지 않는 id 값을 가져오라고 한다면?
const result = document.getElementById(id);
}
catch(e){
console.log("catch 실행");
console.log(e);
}
finally{
console.log("finally 실행");
}
결과 :
try 실행
catch 실행
ReferenceError: document is not defined
at file:///c:/Users/tnrdu/Documents/GitHub/JavaScript-ES6-/ES6_Study/js/exception.js:4:20
at ModuleJob.run (node:internal/modules/esm/module_job:185:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:281:24)
at async loadESM (node:internal/process/esm_loader:88:5)
at async handleMainPromise (node:internal/modules/run_main:65:12)
finally 실행
위와 같이 존재하지 않는 id 값을 받아오는 명령이 수행되면 익셉션이 발생하게 되어 catch 블록에 들어있는 코드들이 수행되게 된다.
ReferenceError 로 시작되는 로그는 catch 블록에서 console.log(e) 를 통해 출력된 것이다.
익셉션 로그를 정상적으로 출력 시키고 나면 프로그램이 종료되지 않고 finally 블록 안에 있는 코드들이 실행된다.
그런데 여기서 익셉션 로그 전체가 아니라, 그냥 어떤 익셉션이 발생했는지 이름만 확인해보고 싶을 경우 아래와 같이 코드를 작성할 수 있다.
try{
console.log("try 실행")
// 존재하지 않는 id 값을 가져오라고 한다면?
const result = document.getElementById(id);
}
catch(e){
console.log("catch 실행");
// 익셉션 객체의 name 필드만 출력
console.log(e.name);
}
finally{
console.log("finally 실행");
}
결과 :
try 실행
catch 실행
ReferenceError
finally 실행
물론 에러 메세지만 따로 확인하는 것도 가능하다.
try{
console.log("try 실행")
// 존재하지 않는 id 값을 가져오라고 한다면?
const result = document.getElementById(id);
}
catch(e){
console.log("catch 실행");
// 익셉션 객체의 message 필드만 출력
console.log(e.message);
}
finally{
console.log("finally 실행");
}
결과 :
try 실행
catch 실행
document is not defined
finally 실행
익셉션은 단순히 문법상의 오류나, 코드 실행상의 오류로서 발생시키는 것 만이 아니라, 개발자가 throw new 키워드를 통해 Error 객체를 만들어서 직접 익셉션을 발생시킬 수도 있다.
개발자가 익셉션을 직접 일으키는 경우는 보통 프로그램이 어떻게 돌아가는지 확인하기 위한 디버깅을 수행할 때가 있다.
try{
console.log("try 실행")
throw new Error("개발자가 정의한 에러 발생");
}
catch(e){
console.log("catch 실행");
// 익셉션 객체의 message 필드만 출력
console.log(e.message);
}
finally{
console.log("finally 실행");
}
결과 :
try 실행
catch 실행
개발자가 정의한 에러 발생 -> 이와 같이 개발자가 직접 정의한 에러 객체를 생성해서 발생시킬 수도 있다.
finally 실행
Promise, async & await
Promise 는 자바스크립트 비동기 처리에 사용되는 객체이다.
Promise 인스턴스 안에 비동기 처리될 대상을 넣어줄 수 있다.
예시 : asncFunction = new Promise( () => { ... } );
여기서 중괄호 안에 비동기 수행시 어떤 일을 처리할지를 작성하는데, 해당 작업이 경우에 따라 처리 될 수도 있고, 그렇지 않을 수도 있다.
그렇기 때문에 Promise 인스턴스를 생성할 때 다음과 같은 형태로 코드를 작성해준다.
asncFunction = new Promise( (resolve, reject) => { ... } );
- resolve : 비동기 함수가 잘 실행 되었을 때 호출
- reject : 비동기 함수에 문제가 있어 제대로 실행되지 않았을 때 호출
아래의 코드를 보자.
function sayHello(name) {
return new Promise( (resolve, reject) => {
setTimeout(() => {
console.log(`제 이름은 ${name} 입니다.`);
resolve(); // 비동기 처리가 잘 수행 되었으므로 resolve() 함수 호출
}, 2000);
})
}
sayHello("호준");
결과 : 제 이름은 호준 입니다.
위의 코드를 보면 Promise 인스턴스 안에 작성된 setTimeout() 함수 (비동기식 처리 함수) 가 잘 수행 되었음을 확인할 수 있다.
여기서 좀 더 비동기 처리식으로 작성해보자.
function sayHello(name) {
return new Promise( (resolve, reject) => {
setTimeout(() => {
console.log(`제 이름은 ${name} 입니다.`);
resolve();
// reject();
}, 2000);
})
}
// 비동기 함수가 잘 호출된 경우 then 실행,
// 그렇지 않은 경우 catch 실행
sayHello("호준")
.then(() => {console.log(`반갑습니다.`)})
.catch(() => {console.log(`함수가 제대로 실행되지 않았습니다.`)})
결과 :
제 이름은 호준 입니다.
반갑습니다.
위의 코드에서 sayHello() 함수 호출 이후에 붙은 then 과 catch 는 각각 resolve(), reject() 함수가 호출 되었을 때 실행되는 함수들이다.
즉, 비동기식 처리 함수가 문제없이 잘 수행되었을 경우 then 내부에 있는 코드가 실행되고, 그렇지 않은 경우 catch 내부에 있는 함수가 수행되게 된다.
여기서 resolve() 함수의 경우 비동기식 처리가 잘 수행되었을 시 리턴값을 then 함수에 반환해줄 수 있다.
function sayHello(name) {
return new Promise( (resolve, reject) => {
setTimeout(() => {
console.log(`제 이름은 ${name} 입니다.`);
resolve(name); // 비동기 처리가 잘 수행되었을 때 name 변수 리턴
// reject();
}, 2000);
})
}
// 비동기 함수가 잘 호출된 경우 then 실행,
// 그렇지 않은 경우 catch 실행
sayHello("호준")
.then((name) => {console.log(`${name} 님 반갑습니다.`)})
.catch(() => {console.log(`함수가 제대로 실행되지 않았습니다.`)})
결과 :
제 이름은 호준 입니다.
호준 님 반갑습니다.
그런데 이러한 비동기식 처리를 그냥 동기식 처럼 순차적으로 수행시키고 싶을 때가 있다.
그럴 때 사용할 수 있는 것이 ES7 에서 새로 나온 async & await 이다.
대략적으로 아래와 같은 형태를 띄고 있다.
async functionName ( ... ){
const result = await asyncFunction()
}
- async : 해당 키워드가 붙은 함수는 비동기로 처리되는 함수라는 것을 명시해준다.
- await : 해당 키워드가 붙은 함수는 조금 기다렸다가 수행되는 함수라는 것을 명시해준다.
일반적으로 위에서 작성한 바와 같이 sayHello() 함수가 정의되어 있을 때, 해당 함수를 호출해 준 후 다른 함수를 호출하면 자바스크립트의 비동기적인 특징 때문에 2초를 더 기다려야 하는 sayHello() 함수가 먼저 수행되는 것이 아니라, 그 이후에 호출된 함수가 먼저 수행되게 된다.
sayHello();
foo(); // <- foo() 함수가 먼저 수행됨
이를 async & await 을 통해 sayHello() 함수가 먼저 수행되는 동기식 처리로 만들어보자.
function sayHello(name) {
return new Promise( (resolve, reject) => {
setTimeout(() => {
console.log(`제 이름은 ${name} 입니다.`);
resolve(name); // 비동기 처리가 잘 수행되었을 때 name 변수 리턴
// reject();
}, 2000);
})
}
async function foo(name){
// sayHello() 함수의 resolve() 함수가 반환해주는 name 값을 받아온다.
const resultName = await sayHello(name);
console.log(`2초 뒤 실행될 코드`);
}
foo(`호준`);
결과 :
제 이름은 호준 입니다.
2초 뒤 실행될 코드
결과를 보면 함수들이 순차적으로 실행 되었음을 알 수 있다.
* 실전에서의 async & await 는 주로 어떻게 사용될까?
주로 외부 서버의 정보를 현재 서버로 가져와서, 그 정보들을 가공하는 과정에서 잘 쓰인다.
그리고 async & await 과 단짝 친구처럼 붙어다니는 개념이 예외처리 이다.
왜냐하면 async & await 을 통해 비동기식으로 처리되는 코드들을 동기식으로 처리하는 과정에서 익셉션이 빈번하게 발생할 수 있기 때문이다.
즉, async & await 을 try-catch-finally 구문과 함께 사용하면 더 유용한 코드를 작성해 줄 수 있다.
프레임워크를 위한 JavaScript ES6 - 구름EDU
자바스크립트 기반 웹 프레임워크, 막상 시작했지만 너무 막연하게 느껴지나요? 자바스크립트로 프레임워크를 '잘' 사용하는 방법을 알아봅시다.
edu.goorm.io
'JAVASCRIPT' 카테고리의 다른 글
자바스크립트 - 클래스와 모듈 (0) | 2022.02.06 |
---|---|
자바스크립트 - Spread 와 rest (0) | 2022.02.05 |
자바스크립트 - 구조분해 할당(destructuring assignment) (0) | 2022.02.05 |
자바스크립트 - JS 에서의 배열 (0) | 2022.02.05 |
자바스크립트 - 화살표 함수(arrow function) (0) | 2022.02.05 |