본문으로 바로가기

[JavaScript] async await로 비동기 처리 개선하기

이전 게시글 Promise로 callback 지옥 무찌르자에서 확인한 promise로 비동기 처리하는 방법을 조금 더 깔끔하게 처리할 수 있도록 async await을 배워보겠습니다.

async await

◆ 가독성

async await비동기 처리를 보다 더 깔끔하게 처리할 수 있는 방법입니다. 사용은 아래와 같이할 수 있습니다.

async function asyncFn() {
  await 비동기함수();
}

위와 같이 async, await 만 추가하면 사용할 수 있습니다. 그럼 이게 왜 promise만 사용하는 것보다 더 좋을까요? 우선 가독성이 promise 보다 더 좋습니다. 아래 예시를 참고해봅시다.

function getData_1() {
  return new Promise(resolve => {
    resolve("data1");
  });
}

function getData_2() {
  return new Promise(resolve => {
    resolve("data2");
  });
}

getData_1().then(console.log).then(getData_2).then(console.log);

promise를 사용하여 비동기 처리를 하게 되면 위와 같이 작성해야합니다. 그럼 .then.then.then으로 chaining을 하여야 하는데 개수가 늘어나면 가독성이 좋지 않습니다. async await은 문제를 쉽게 해결할 수 있습니다.

function getData_1() {
  return new Promise(resolve => {
    resolve("data1");
  });
}

function getData_2() {
  return new Promise(resolve => {
    resolve("data2");
  });
}

(async () => {
  const data_1 = await getData_1();
  const data_2 = await getData_2();

  console.log("data_1", data_1);
  console.log("data_2", data_2);
})();

간단하게 함수를 사용하기 위해 즉시 실행 함수를 사용하였습니다. 우선 chaining이 없어져 더 코드가 깔끔해보이죠? 가독성이 더 좋아집니다.

◆ 서로 연관 있는 비동기, 연관 없는 비동기

추가로 비동기 처리할 때 사용하면 좋은 함수 몇 가지를 소개해드리겠습니다. 비동기 함수를 여러 개 처리할 때 중요한 것 중 하나는 각각의 비동기 처리에 대해 서로 연관이 있는 지 없는 지 입니다. 우선 서로 연관이 있는 비동기 처리 먼저 확인해보겠습니다. 아래 비동기 코드는 getData_2를 실행하기 위해서는 앞서 꼭 getData_1이 실행되어야 합니다.

function getData_1() {
  return new Promise(resolve => {
    setTimeout(() => resolve("data1"), 3000);
  });
}

function getData_2() {
  return new Promise(async resolve => {
    setTimeout(() => resolve("data2"), 3000);
  });
}

async function getDatas() {
  const data1 = await getData_1();
  const data2 = await getData_2();

  return [data1, data2];
}

getDatas().then(console.log);

위 코드를 실행하면 총 6초가 소요됩니다. getData_1 함수에서 3초, getData_2 함수에서 3초가 소요되기 때문입니다. 이 경우는 어쩔 수 없습니다. 순서가 정해져있기 때문이죠. 꼭 getData_2를 실행하기 위해서는 사전 작업인 getData_1이 시작되어야 하기 때문입니다. 그러나 만약 2개의 비동기 함수가 서로 순서에 영향을 미치지 않으면 어떻게 될까요? 굳이 getData_1이 실행되고 나서 getData_2를 실행시키는 것이 아니라 동시에 실행시켜도 되겠죠? 이러한 것을 할 수 있도록 하는 함수가 Promise.all 함수 입니다. 아래 코드를 확인해봅시다.

function getData_1() {
  return new Promise(resolve => {
    setTimeout(() => resolve("data1"), 3000);
  });
}

function getData_2() {
  return new Promise(async resolve => {
    setTimeout(() => resolve("data2"), 3000);
  });
}

function getDatas() {
  return Promise.all([getData_1(), getData_2()]);
}

getDatas().then(console.log);

위 함수를 실행하면 3초가 소요됩니다. getData_1, getData_2를 동시에 호출하기 때문입니다. 이렇게 서로 연관이 없는 비동기 처리는 동시에 요청할 수 있습니다. 그런데 이러한 경우도 있을 수 있습니다. 선착순 즉, 더 빨리 응답이 온 비동기 처리가 필요하다. 어떤 비동기 처리인지는 모르겠고 더 빨리 응답이 온 것이 필요하다. 이러한 경우는 Promise.race 함수를 사용하시면 됩니다. 아래 코드를 확인해봅시다.

function getData_1() {
  return new Promise(resolve => {
    setTimeout(() => resolve("data1"), 1000);
  });
}

function getData_2() {
  return new Promise(resolve => {
    setTimeout(() => resolve("data2"), 3000);
  });
}

function getData() {
  return Promise.race([getData_1(), getData_2()]);
}

getData().then(console.log);

이러한 경우는 getData_1이 1초로 더 빠르게 응답이 오기 때문에 data1만 출력이 된 것을 확인할 수 있습니다 (직접 코드를 실행해보세요).

 

여기까지 callback, callback 지옥, promise, async await를 알아보았습니다. 도움이 약간이라도 되면 좋겠습니다.

참고자료

마지막

해당 내용은 틀릴 수도 있습니다. 틀린 내용이 있으면 조언 부탁드립니다.

반응형