async와 await

se-een·2023년 3월 30일
0
post-thumbnail

이 글은 '이웅모'님의 '모던 자바스크립트 Deep Dive' 책을 통해 공부한 내용을 정리한 글입니다. 저작권 보호를 위해 책의 내용은 요약되었습니다.

async / await

제너레이터를 통해 비동기를 동기 처리처럼 동작하도록 구현하였지만, 코드의 가독성이 매우 떨어지는 문제점을 야기했다. ES8에서는 async / await가 제너레이터를 대신할 수 있게 되었다.

프로미스 기반

async / await는 프로미스를 기반으로 동작한다. 프로미스의 후속 처리 메서드 없이 동기 처리처럼 프로미스의 처리 결과를 반환하도록 구현할 수 있다.

async 함수

async 함수는 항상 프로미스를 반환한다. 따라서 프로미스가 아닌 값도 Promise.resolve를 통해 이행된 프로미스가 반환되도록 한다.

async function foo() {
  return 1;
}

foo(); // Promise {<fulfilled>: 1}
foo().then(console.log); // 1

아래 코드는 약 1초 후 6개의 요소로 이루어진 배열이 Promise 객체의 결과값([[PromiseResult]])으로 반환된다.

async function getPopularMovie() {
  await new Promise((resolve) => setTimeout(resolve, 1000));
  return ["장화신은 고양이", "똑똑똑", "와칸다 포에버", "다이 하트", "플레인", "아바타: 물의 길"];
}

getPopluarMovie(); // Promise {<fulfilled>: Array(6)}
// ["장화신은 고양이", "똑똑똑", "와칸다 포에버", "다이 하트", "플레인", "아바타: 물의 길"]

await 키워드

await 키워드는 말 그대로 '기다린다.'라는 의미의 동작을 수행한다. 즉 프로미스가 처리(settled)될 때까지 코드의 동작을 일시정지 시킨다. 이로써 비동기처리를 마치 동기처리처럼 보일 수 있게 하는 것이다.

await 키워드는 반드시 async 함수 내부에서만 사용해야 한다.

단, await 키워드는 다음 실행을 일시 중지시킨다는 특징이 있기에, 상황에 맞게 잘 고려하여 사용해야 한다.

async function foo() {
  const a = await new Promise(resolve => setTimeout(() => resolve(1), 3000));
  const b = await new Promise(resolve => setTimeout(() => resolve(2), 2000));
  const c = await new Promise(resolve => setTimeout(() => resolve(3), 1000));
  
  return [a, b, c];
}

// 약 6초의 시간이 걸린다.
foo(); // Promise {<fulfilled>: Array(3)} [1, 2, 3]

위 코드에서는 a, b, c 모두 서로와 관련이 없으므로 비동기로 개별 진행 후 한 번에 처리하는 것이 더 효율적이다. 따라서 다음과 같이 수정해볼 수 있다.

async function foo() {
  const result = await Promise.all([
    new Promise(resolve => setTimeout(() => resolve(1), 3000));
    new Promise(resolve => setTimeout(() => resolve(2), 2000));
    new Promise(resolve => setTimeout(() => resolve(3), 1000));
  ]);
  
  return result;
}

// 약 3초의 시간이 걸린다.
foo(); // Promise {<fulfilled>: Array(3)} [1, 2, 3]

즉, 실행 흐름이 보장되어야만 하는 상황인지 아닌지를 파악하여 await 키워드를 사용하는 것이 좋겠다.

에러 처리

기존의 콜백 함수에서는 try catch문을 사용하여 에러 처리를 하는 것이 불가능했다. 비동기 함수인 콜백 함수를 호출한 것이 비동기 함수가 아니기 때문이기에 그렇다.

async / await에서는 try catch문을 통해 에러 처리를 할 수 있다. HTTP 통신에서 발생한 네트워크 에러뿐만 아니라 try 코드 블록 내의 모든 문에서 발생한 일반적인 에러까지 모두 캐치 가능하다.

async 함수 내에서 catch 문을 통한 에러 처리를 진행하지 않으면, 발생한 에러를 reject하는 프로미스를 반환한다.

const foo = async () => {
  try {
    const URL = 'https://www.abc.com';
    
    const response = await fetch(URL);
    const responseData = await response.json();
    
    console.log(responseData);
  } catch (e) {
    console.error(e);
  }
};

foo();
profile
woowacourse 5th FE

0개의 댓글