비동기 통신(2): async, await

최건우·2023년 1월 31일
0

자바스크립트

목록 보기
2/3

async, await

async, await는 비동기 함수를 표준 동기 함수를 사용하는 것처럼 간단하게 쓸 수 있게 해 준다.

async

어떤 함수 앞에 async 키워드를 붙이면, 해당 함수는 항상 Promise를 반환한다. 혹은, Promise가 아니더라도 이행 상태(resolved)의 promise로 값을 감싸, resolved promise가 반환되도록 한다.

await

await는, 앞서 정의한 async 함수를 실행할 때만 사용 가능하다.

자바스크립트는 await 키워드를 만나면, Promise가 처리될 때까지 실행을 중단한다. 그리고 결과는 Promise가 처리된 실행을 재개한다.

async 함수의 본문은 await가 포함되어야만 비동기적으로 실행된다. 만약 async 함수가 await 없이 실행된다면, 동기적으로 실행된다.

async function f() {

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("완료!"), 1000)
  });

  let result = await promise; // Promise가 이행될 때까지 기다림 (*)

  alert(result); // "완료!"
}

f();

위 예시에서 f() 함수의 본문은 중간에 await promise;로 된 구간에서 실행이 잠시 중단되었다가, promise가 처리되면 실행이 재개된다. 이때, 변수 let result에는 Promise 객체인 promise의 결괏값이 할당된다.

이때, 프라미스가 처리되는 동안에는 엔진은 다른 스크립트를 실행하거나, 이벤트 처리를 할 수 있기 때문에 CPU 리소스가 낭비되지 않는다.

awaitpromise.then보다 가독성 좋고 쓰기 쉬운 코드로 결괏값을 얻을 수 있게 해 주는 문법이다.

await 유의사항

await는 최상위 레벨 코드에서는 작동하지 않는다. 하지만, 익명 async 함수로 감싸면 최상위 레벨에서도 사용 가능하다.

let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();

------------------------------------
/* 하지만, 익명 async 함수로 감싸면 최상위 레벨에서도 사용 가능! */
(async () => {
  let response = await fetch('/article/promise-chaining/user.json');
  let user = await response.json();
  ...
})();

에러 핸들링

  • Promise가 정상적으로 이행(fulfilled)되면 await promise는 Promise 객체의 result에 저장된 값을 반환한다. 반면 Promise가 거부(rejected)되면 마치 throw문을 작성한 것처럼 예외가 생성되는 형태로 에러가 던져진다.
async function f() {
  await Promise.reject(new Error("에러 발생!"));
}

---------
/* 위 코드는 아래와 동일하다. */
async function f() {
  throw new Error("에러 발생!");
}
  • async 함수에서는 throw를 활용해 에러를 발생시키고, await promise의 에러는 throw가 던진 에러를 잡을 때처럼 try...catch를 사용해 잡는다.
async function f() {

  try {
    let response = await fetch('http://unavailable-url');
    let user = await response.json();
  } catch(err) {
    // fetch와 response.json에서 발행한 에러 모두를 여기서 잡음.
    alert(err);
  }
}

f();
  • async 함수 내부에서 try...catch로 적절히 에러를 제어해 주지 않는다면, async 함수를 호출해 만든 Promise는 거부(rejected) 상태가 된다.

  • 이럴 경우, .then(), .catch()를 사용하면 거부된 Promise를 처리할 수 있다.

async function f() {
  let response = await fetch('http://unavailable-url');
}

// f()는 거부 상태의 프라미스가 된다. .catch를 사용해 처리한다.
f().catch(alert); // TypeError: failed to fetch

async/await로 여러 개의 Promise 처리하기

  • 여러 개의 Promise가 모두 처리되길 기다려야 한다면, 이 Promise들을 Promise.all()로 감싸고 여기에 await를 붙여 사용할 수 있다. 이때, 등록한 프로미스 중 하나라도 실패하면, 모든게 실패한 것으로 간주한다.
Promise 처리 결과가 담긴 배열을 기다린다.
let results = await Promise.all([
  fetch(url1),
  fetch(url2),
  ...
]); // 등록된 모든 프로미스가 성공해야 results가 성공한 것으로 간주된다.
  • 실패한 프라미스에서 발생한 에러는 보통 에러와 마찬가지로 Promise.all로 전파된다. 에러 때문에 생긴 예외는 try..catch로 감싸 잡을 수 있습니다




출처

profile
부족한 경험을 채우기 위한 나만의 기록 공간

0개의 댓글