자바스크립트 async, await

async await 명령어는 자바스크립트에서 비동기 코드를 더 직관적이고 동기적인 방식으로 작성할 수 있게 해주는 문법입니다.

이 두 가지는 Promise 객체를 기반으로 동작하며, 비동기 작업을 보다 쉽게 처리할 수 있도록 도와줍니다.

async await 기본 개념

  • async:
    • 함수 앞에 async를 붙이면 해당 함수는 Promise 객체를 반환합니다.
    • 함수 내부에서 await을 사용할 수 있게 되어 비동기 코드를 동기처럼 작성할 수 있습니다.
  • await:
    • 이는 async 함수 내에서만 사용할 수 있으며, Promise 객체가 처리될 때까지 기다립니다.
    • Promise가 해결되면 await는 해당 Promise의 결과 값을 반환하고, Promise가 거부되면 에러를 던집니다.

예제 1: 기본적인 사용

function fetchData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("데이터 가져오기 완료");
    }, 2000);
  });
}

async function getData() {
  console.log("데이터 요청 중...");
  const result = await fetchData();
  console.log(result);
}

getData();
async await 기본 사용

위의 예제를 개발자 도구에서 실행하면 이미지와 같은 결과를 얻을 수 있습니다.

먼저 getData() 함수가 async로 정의되어 있고, 그 내부에서 fetchData()라는 비동기 함수를 await 명령어로 기다리고 있습니다.

여기서 fetchData() 함수가 끝날 때까지 기다린 후, result에 그 값을 할당하고 console.log() 메소드를 통해 메시지를 출력합니다.

예제 2: 여러 비동기 작업을 순차적으로 처리

function task1() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Task 1 완료");
    }, 1000);
  });
}

function task2() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Task 2 완료");
    }, 500);
  });
}

async function executeTasks() {
  const result1 = await task1();
  console.log(result1);
  
  const result2 = await task2();
  console.log(result2);
}

executeTasks();
여러 비동기 작업을 순차적으로 처리

이번 예제에서 task1() 함수와 task2() 함수는 각각 1초, 0.5초 후에 완료되는 비동기 작업입니다.

executeTasks()에서는 await을 사용하여 각 작업을 순차적으로 처리하도록 했습니다.

예제 3: 병렬 실행 후 결과 처리 (Promise.all, async, await 결합)

비동기 작업을 병렬로 실행해야하는 경우에는 Promise.all과 await을 결합하여 사용할 수 있습니다.

Promise.all은 배열의 모든 Promise가 해결되거나 하나라도 거부되면 결과를 리턴합니다.

function task1() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Task 1 완료");
    }, 1000);
  });
}

function task2() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Task 2 완료");
    }, 500);
  });
}

async function executeTasks() {
  const results = await Promise.all([task1(), task2()]);
  console.log(results);
}

executeTasks();
async await promise.all

스크립트에서 task1() 함수와 task2() 함수는 병렬로 실행됩니다.

하지만 await Promise.all()을 사용하여 두 작업이 모두 완료될 때 까지 기다렸다가 메시지를 출력했습니다.

예제 4: try-catch로 에러 처리하기

Promise 객체로 비동기 작업을 처리할 때, 작업이 실패하면 catch() 메소드로 처리할 수 있었습니다.

이번에는 async 함수 내부에서 try…catch 문을 사용하여 비동기 작업 중 발생한 에러를 처리해 보겠습니다.

function task1() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Task 1 완료");
    }, 1000);
  });
}

function task2() {
  return new Promise((_, reject) => {
    setTimeout(() => {
      reject("Task 2 에러 발생");
    }, 500);
  });
}

async function executeTasks() {
  try {
    const result1 = await task1();
    console.log(result1);
    
    const result2 = await task2();
    console.log(result2);
  } catch (error) {
    console.error("에러 발생:", error);
  }
}

executeTasks();
async await try catch

이번 스크립트에서는 task2() 함수가 실패하고 reject()를 호출합니다.

이를 try…catch 구문으로 감싸면 에러를 처리할 수 있게됩니다.

예제 5: HTTP 요청 예제

API 서버와 통신할 때 async await을 많이 사용합니다.

다음은 fetch API를 사용하여 외부 API에서 데이터를 받아오는 예제입니다.

async function fetchPosts() {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  const posts = await response.json();
  console.log(posts);
}

fetchPosts();

여기서는 fetch API를 사용해 외부 서버에서 데이터를 가져옵니다.

await을 사용하여 응답이 올 때까지 기다리고, json() 메소드로 JSON 데이터를 파싱하여 출력합니다.

async await의 장점

  • 가독성: 콜백 함수나 then 체이닝을 사용할 때보다 더 읽기 쉽고, 동기적인 코드처럼 작성할 수 있어 가독성이 높습니다.
  • 에러 처리: try-catch 블록을 사용하여 동기 코드처럼 자연스럽게 에러를 처리할 수 있습니다.
  • 비동기 코드 작성: 복잡한 비동기 코드를 async/await으로 작성하면 더 직관적이게되고 오류를 줄일 수 있습니다.

정리

async/await은 비동기 작업을 처리하는 매우 유용한 도구입니다.

Promise 객체를 기반으로 동작하지만, 콜백 지옥이나 복잡한 then() 체이닝을 피할 수 있고, 동기 코드처럼 작성할 수 있어 훨씬 가독성이 좋습니다.

이런 기능을 통해 다양한 비동기 작업을 보다 효율적이고 간단하게 처리할 수 있게 도와줍니다.

관련 글

자바스크립트 튜토리얼