관리 메뉴

Jerry

async 예외처리(의 까다로운점?) 본문

Front/JavaScript

async 예외처리(의 까다로운점?)

juicyjerry 2021. 4. 15. 13:37
반응형

어제 async await에 대해 정리해보았다. (관련 포스트)

 

오늘은 async를 사용할 경우, 예외 처리하는 법은 어떻게 하는지 알아볼 것이다!

 

준비됐나??

 

출처: 구글 이미지

 

시작해보자!

 

자 저번 글에 이야기 했지만 큰 그림을 위해서 + 복습 차원에서 아는 코드를 예시로 먼저 보도록 하겠다.

#1의 result값과 #2의 result값은 무엇일까? 

조금이라도 생각해보고 휠을 내려보자!

 

#1
async function myAsyncFunction() {
  return 'done';
}

const result = myAsyncFunction();
console.log(result);



#2
function myPromiseFun() {
    return new Promise((resolve, reject) => {
        resolve('done');
    })
}


const result2 = myPromiseFun();
console.log(result2);

 

그 결과는 당연하게도...

아래에 보이는대로 동일한 값을 반환한다. 

그 이유는 aync가 붙은 함수는 프라미스를 반환 값으로 보내기 때문이다.

 

 

 

 

 

 

그렇다면... 

거절될 경우는 코드로 어떻게 표현할 수 있을까?

보기전, 가급적 조금이라도 생각해보자!

 

#3
function myPromiseFun() {
    return new Promise((resolve, reject) => {
        reject('done');
    })
}


const result3 = myPromiseFun();
console.log(result3);

 

너무나 간단한 질문이었다. 

resolve를 reject로 바꿔주면 된다.

 

 

그러면 async 함수에서는 어떻게 사용할까?

이것도 보기 전 가급적 생각해보자!

#4
async function myAsyncFunction() {
  throw 'myAsyncError!';
}

const result4 = myAsyncFunction();
console.log(result4);

 

보이시는 대로 return '반환 값' 대신에 throw로 에러 처리를 해주었다.

프라미스와 다르게 async 함수에서 동기적으로 에러 처리가 되었다.

 

 

참고로, mdn 가라사대 throw는 이렇다고 한다.

 

The throw statement throws a user-defined exception. Execution of the current function will stop (the statements after throw
 won't be executed), and control will be passed to the first catch block in the call stack. If no catch block exists among caller functions, the program will terminate.

 => throw문은 유저가 정의한 예외처리라고 한다. 현재 함수의 실행을 멈추고 콜 스택 안의 첫 번째 catch 블록에게 control이 전달된다. 만약 catch 블록이 caller 함수 사이에 없다면, 프로그램은 종료될 것이다. 

 

 

 

콘솔 값이 어떻게 찍혔는지 직접 크롬 개발자 도구를 열어 확인해보자!

 

 

필자는 위 내용처럼 나왔는데, 이와 다르게 'Uncaught' 에러가 발생한 분도 계실 거다.

그런 경우는 자연스러운 상황이니 당황하지 마시라!

 

 

프라미스 구문(아래 #3)은 reject로 비동기 예외처리를 해주었지만 async 구문(아래 #4)의 비동기 예외처리는 어떻게 해주어야 할까?

#3이나 #4나 어차피 같은 프라미스 값을 반환하기 때문에 catch문을 사용해서 예외처리를 해주면 #3과 동일하게 비동기적으로 예외처리가 가능해진다! 

 

#3
function myPromiseFun() {
    return new Promise((resolve, reject) => {
        reject('done');
    })
}

const result3 = myPromiseFun().catch(e => {
  console.error(e);
})


#4
async function myAsyncFunction() {
	throw 'myAsyncError!';
}

const result4 = myAsyncFunction().catch(e => {
  console.error(e);
})

 

 

위 코드에 대한 콘솔 값은 이렇게 나온다.

 


 

여기까지 async 사용 시 예외처리에 대해서 잘 알아보았다. 

마지막으로 async 사용할 때, 예외 처리하는 다른 방법에 대해 살펴보겠다! 

 

코드를 살펴보자!

#1
function wait(sec) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('wait Error!');
        }, sec * 1000);
    });
}

async function myAsyncFun() {
    console.log(new Date());
    await wait(3);
    console.log(new Date());
}

const result = myAsyncFun();

 

#1을 실행시켜보면 아래와 같이 값이 나온다.

첫 번째 new Date() 값은 찍혔지만 두 번째 new Date() 값은 찍히지 않았다. 왜 그럴까?

 

 

 

왜냐하면, await wait(3)에서 reject 당해서 두번째 new Date()로 넘어가질 못했던 것이다. 다르게 생각해보면, 만약 reject이 아니라 fullfilled 상태가 되었다면 두번째 new Date()는 실행이 될 것이다.

 

 

흠... 이걸 알려주려고 이야기를 또 꺼낸 게 아닐 텐데... 뭔가 찝찝한데.. 하는 느낌과 함께 "뭔가 이런 상황을 해결할 수 있는 예외 처리 방법이 있을 거 같은데..?"라고 생각하신 분이 계실까 모르겠다 😎😎😎

 

 

이런 상황에서 사용할 수 있는 문법으로 try... catch문이 존재한다! 

 

#2
function wait(sec) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('wait Error!');
        }, sec * 1000);
    });
}

async function myAsyncFun() {
    console.log(new Date());
    try {
      await wait(3);
    } catch(e) {
      console.error(e);
    }
	  console.log(new Date());
}

const result = myAsyncFun();

 

위 같이 하게 되면 결과는 아래와 같다.

 

 

 

또한 #2를 #2-1처럼 사용할 수 있기도 한데, 주의해야 할 점이 있다. 

 

#2-1
function wait(sec) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('wait Error!');
        }, sec * 1000);
    });
}

async function myAsyncFun() {
    console.log(new Date());
    const result = await wait(3).catch((e) => {
      console.error(e);
    });
      console.log(result); // !!
      console.log(new Date());
}

const result = myAsyncFun();

 

주석으로 '!!' 표시한 부분이 undefined가 나올 수 있다. 

아래 결과를 보시면, 첫 번째 undefined는 크롬 개발자 도구에서 console.log 찍으면  자동으로 나오는 친구고 우리가 봐야 할 것은 두 번째다(!! 부분). 

 

 

result가 undefined인 이유는 catch 문에서 어떤 값도 리턴하지 않기 때문이다! 

 

 

 

이렇듯 해당 비동기 처리 키워드에 catch문을 사용해서 예외 처리를 할 수 있듯이 

async 함수 내에 오타나 기타 이유로 에러가 나는 상황에 대해 함수 자체에 catch문을 붙여 예외처리를 할 수도 있다. 

 

async function myAsyncFun() {
    consoldgsge.log(new Date()); // error! 
    const result = await wait(3).catch((e) => {
      console.error(e);
    });
      console.log(result); // !!
      console.log(new Date());
}

#1
const result = myAsyncFun().catch((e) => {
  console.error(e);
})

#2
try {
  myAsyncFun();
} catch (e) {}

 

#1처럼 #2처럼 사용할 수 있다. 

 

여기까지 async 예외처리에 대해서 자세하게 살펴보았다. 

피가 되고 살이 되는 시간이었기를 바란다. 💪💪💪💪💪

 

 

 

참고: 코드종 | bit.ly/3tm8Pqv

참고: MDN | mzl.la/3tlHvsq

 

반응형

'Front > JavaScript' 카테고리의 다른 글

실행 콘텍스트(Execution Context)란?  (0) 2021.04.19
이벤트 루프란? (in Javascript)  (2) 2021.04.16
자바스크립트 원시값?  (1) 2021.04.14
async await 이란?  (0) 2021.04.14
One Paper: Understanding Prototype  (0) 2020.11.07