[Effective Typescript - 아이템 25] async: 콜백, 프로미스 대신 사용하는 비동기 함수

Song·2021년 12월 29일
0
post-custom-banner

비동기 함수란,

하나의 작업만 수행할 수 있는 자바스크립트의 단점을 보완하기 위한 함수.
비동기 함수를 이용하면 특정 코드의 처리가 끝날 때까지 다음 코드가 기다리지 않아도 되며
특정 코드는 다른 곳 (aka 이벤트 루프)에서 실행된 후 반환된다.

async/await를 사용해야하는 이유

  • 일반적으로 더 간결하고 직관적인 코드가 된다.
  • 프로미스를 반환하도록 강제한다.

1. 일반적으로 더 간결하고 직관적인 코드가 된다.

1️⃣. 콜백 함수

fetchURL(url1, function (response1) {
  fetchURL(url2, function (response2) {
    fetchURL(url3, function (response3) {
      console.log(1);
    });
    console.log(2);
  });
  console.log(3);
});
console.log(4);

// 로그
// 4
// 3
// 2
// 1

JS 초창기 비동기 함수를 구현할 때 사용하던 방식으로 하나 이상의 함수를 실행시킬 때 코드들이 중첩되어 있어 가독성이 떨어지고 실행 순서 역시 코드의 순서와 반대로 직관적으로 어려운 코드가 구현된다.

2️⃣. 프로미스

const page1Promise = fetch(url1);
page1Promise
  .then((response1) => {
    return fetch(url2);
  })
  .then((response2) => {
    return fetch(url3);
  })
  .then((response3) => {
    return fetch(url4);
  })
  .catch((err) => {});

콜백 함수의 문제를 해결하기 위해 ES2015부터 생긴 개념이다.
위 예제는 Promise Chaning으로 then()을 이용해서 비동기 함수를 순차적으로 처리하여
코드의 중첩을 없애고 가독성을 높여 직관적으로 이해하기 수월
해진걸 볼 수 있다.

3️⃣. async/await

async function fetchPages() {
  try {
    const response1 = await fetch(url1);
    const response2 = await fetch(url2);
    const response3 = await fetch(url3);
  } catch (e) {}
}

ES2017부터 도입된 키워드로 Promise 함수를 간결하게 표현할 수 있는 함수다.
await는 각 코드가 resolve를 반환할 때까지 대기하며 reject 반환 시 예외를 던져
미리 감싸놓은 try/catch 문을 이용하여 예외처리를 할 수 있다.

2. Promise를 반환하도록 강제한다.

우리가 작성하는 코드는 항상 동기 또는 비동기로 실행된다.
이 때 두가지가 혼용되서는 안되는데 async는 항상 promise를 반환하므로 일관적으로 비동기 함수를 구현할 수 있도록 도와준다.

또한, Promise는 타입스크립트에서 중요한 기능 중 하나인 타입추론이 잘되기에
아래와 같이 async 함수를 사용하면 따로 리턴 타입을 명시하지 않아도 자동으로 타입이 추론된다.

// 리턴 타입을 명시하지 않아도 Promise<number>로 리턴 타입이 추론된다.
async function getNumber() {
    return 42
}
// 화살표 함수에도 동일하게 적용이 가능하다.
const getNumber = async () => 42

요약

  • 콜백보다는 타입 추론이 잘 작동하는 프로미스를,
  • 프로미스보다는 직관적인 async/await을
  • 물론 async로 표현하기 어려운 promise 기능들이 있으니 상황에 맞춰 잘 사용하자.

플러스 - await마다 에러처리 해주기

  1. await마다 다른 에러 처리를 하고싶을 때
  2. await에서 발생한 오류를 원하는 타이밍에 사용하고 싶을 때
  3. try/catch가 없으므로 스코프 제한 없이 결과 및 에러 사용 가능
const errorFunction = (promise) => {
  try { 
     // 실제 비동기 함수가 실행되는 곳, 성공 시 첫번째 배열에만 값을 넣고 리턴한다. 
     const result =  await promise;
     return [result, null]
  } catch (err) {
    // 함수 실행 중 오류 발생 시 두번째 배열에만 에러내용을 넣고 리턴한다.
    return [null, err ]
  }
}

// 첫번째 배열에 값이 있으면 성공, 두번째 배열에 값이 있으면 에러가 난 것을 확인할 수 있다.
const [ prSuccess, prError ] = await errorFunction(promiseFunction)
if(prError) console.error(prError) 


profile
Learn From Yesterday, Live Today, Hope for Tomorrow
post-custom-banner

0개의 댓글