기능을 구현하다보면 내부에서 단계별로 동작해야하는 코드들이 존재하기 마련이다. 그런데 기능이 수행되는 동안에 에러가 발생하였다면? 그 즉시 전체 기능을 중단하여야 한다. 이를 위해서 사용하는 개념이 바로 try-catch문이다.
try {
console.log('ok!');
}
catch () {
console.log('error!');
}
try 문 내부에서는 기능 수행을 위해 동작해야하는 코드를, catch 문 내부에는 기능 수행 중 에러가 발생하였을 때 동작하는 코드를 작성하면 된다. try 문 내부에 작성한 코드를 실행하는 도중에 에러가 발생했을 경우, JS는 그 즉시 나머지 코드의 실행을 중단하고 제어권을 catch 문으로 넘긴다.
그런데 try-catch문에서 비동기 통신이 사용되는 기능을 적용했을 경우, 에러가 발생되어도 catch 문으로 넘어가지 않는다. 그 이유는, 자바스크립트의 특성상 통신의 결과가 도달하기 전에 try 문이 모든 동작을 완료해버리기 때문이다.
예시) 출처.
try {
setTimeout(function() {
throw Error('에러 발생');
}, 3000);
}
catch (err) {
console.log('에러 핸들링: '+ err.message);
}
console.log('코드 종료.');
setTimeout(function() {
try {
throw Error('에러 발생');
}
catch (err) {
console.log('에러 핸들링: '+err.message);
}
}, 3000);
console.log('코드 종료.');
다음과 같이 비동기 통신 작업을 수행하는 코드 내부로 try-catch문을 집어넣거나..
then-catch문을 사용하면 된다.
비동기통신()
.then(() => {
console.log('ok!');
})
.catch((error) => {
console.log('error!');
})
then-catch문은 사용자가 따로 코드를 추가할 필요가 없고, 에러가 발생했을 때 알아서 catch문으로 넘어가준다.
편리해졌지만, 비동기 통신을 수행하는 코드가 많아질 수록 then-catch문이 중첩되기 때문에 결과적으로 코드의 가독성이 떨어지는 문제를 가지고 있다.
const connect = async () => {
try {
await 비동기통신();
console.log('ok!');
}
catch () {
console.log('error!');
};
};
기존 Promise 객체의 단점을 해결하기 위해 등장한 async, await 키워드는 위와 같은 단점을 개선할 수 있다.
try {
await 비동기통신1();
await 비동기통신2();
await 비동기통신3();
console.log('ok!');
}
catch () {
console.log('error!');
};
각각의 비동기통신을 수행하는 과정에서 에러가 발생할 경우 어느 지점에서든 동작을 중단하고 바로 catch 문으로 넘어가게 된다. 비동기 통신 하나마다 then-catch문을 작성했던 때와 비교해보면 코드가 굉장히 보기 좋아졌다고 할 수 있다.
다만 async, await 키워드에도 단점이 존재한다.
try {
const a = await 비동기통신1();
const b = await 비동기통신2();
const c = await 비동기통신3();
console.log('ok!');
}
catch () {
console.log('error!');
};
모든 코드가 try 문 내부에 존재하다보니 각각의 통신 결과값들이 한 곳에 모여 서로 접근이 가능하다. 같은 상황에서 then-catch문은 하나의 then 문은 하나의 비동기통신 결과값만을 다룰 수 있어 접근이 불가능하므로 내가 구현할 기능의 특징에 맞춰 더 나은 수단을 선택하면 된다.
이 단점은 아마 보안 등의 이유로 단점이라고 하는 듯 한데, 더 자세히 알아볼 것!
then 문이 통신 결과값을 다루는 방법?
.then((response) => {
console.log(response);
// 결과값은 response으로 담아져나온다.
})