카테고리 없음

TypeScript 29강: 비동기 프로그래밍 – Promise와 async/await 완벽 분석

mystory55776 2025. 5. 29. 23:46

비동기 프로그래밍이란?

비동기 프로그래밍은 코드가 실행되는 동안 시간이 걸리는 작업(예: 네트워크 요청, 파일 읽기 등)을 기다리지 않고, 다음 코드를 계속 실행하도록 하는 방식입니다. JavaScript와 TypeScript는 비동기 처리에 매우 최적화된 언어로, Promiseasync/await 문법을 통해 효율적인 비동기 처리를 제공합니다.

타입스크립트에서 Promise 사용하기

Promise는 비동기 작업의 완료 또는 실패를 나타내는 객체입니다. TypeScript에서는 제네릭 타입을 활용해 Promise의 반환 타입을 명확히 지정할 수 있습니다.

function fetchData(): Promise {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("데이터 로딩 완료");
    }, 1000);
  });
}

fetchData().then((result) => {
  console.log(result); // "데이터 로딩 완료"
});

이와 같이 타입이 지정되면 result가 string 타입이라는 것을 컴파일 타임에 알 수 있어, 안전한 코딩이 가능합니다.

async/await 문법의 기본

async 함수는 항상 Promise를 반환하며, await 키워드를 사용하면 비동기 코드를 동기적으로 작성하는 것처럼 만들 수 있어 가독성이 향상됩니다.

async function load() {
  const data = await fetchData();
  console.log(data); // "데이터 로딩 완료"
}

load();

동기 코드처럼 보이지만 내부적으로는 여전히 비동기적으로 작동합니다. 오류 처리도 try/catch 문을 통해 간편하게 할 수 있습니다.

비동기 함수의 타입 명시

TypeScript에서는 비동기 함수의 반환 타입을 Promise<타입> 형태로 명시할 수 있습니다.

async function getUser(): Promise<{ id: number; name: string }> {
  return { id: 1, name: "홍길동" };
}

이처럼 정확한 타입 정의는 실무에서 타입 안전성과 유지보수성을 높이는 데 도움이 됩니다.

실제 예제: fetch를 이용한 API 호출

TypeScript에서 fetch API를 사용할 때도 비동기 방식으로 데이터를 요청할 수 있습니다. 응답 데이터에 대한 타입도 명확히 지정할 수 있습니다.

interface Post {
  id: number;
  title: string;
  body: string;
}

async function fetchPost(id: number): Promise {
  const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  if (!response.ok) throw new Error("네트워크 응답 실패");
  const data = await response.json();
  return data;
}

fetchPost(1).then(post => {
  console.log(post.title);
});

이 예제는 네트워크 요청의 성공 여부와 JSON 파싱을 안전하게 처리하며, API 응답 타입도 명확하게 관리합니다.

비동기 처리에서의 에러 핸들링

비동기 코드에서는 try/catch 블록을 사용해 오류를 쉽게 처리할 수 있습니다.

async function safeFetch() {
  try {
    const data = await fetchData();
    console.log("결과:", data);
  } catch (error) {
    console.error("에러 발생:", error);
  }
}

실무에서는 네트워크 실패, 파싱 오류 등 다양한 문제가 발생할 수 있기 때문에 에러 처리는 필수입니다.

Promise.all과 병렬 처리

여러 개의 비동기 작업을 병렬로 처리할 때는 Promise.all을 사용하면 효율적입니다.

async function loadAll() {
  const [post1, post2] = await Promise.all([fetchPost(1), fetchPost(2)]);
  console.log(post1.title, post2.title);
}

이 방식은 동시에 여러 작업을 처리하여 성능을 향상시킬 수 있습니다.

async/await vs Promise 체이닝

.then() 체이닝 방식과 async/await 방식은 기능적으로 같지만, async/await는 가독성이 높고 에러 핸들링이 간편한 장점이 있습니다.

  • then 체이닝: 짧은 코드에는 유리하지만 중첩되면 가독성이 떨어짐
  • async/await: 복잡한 로직에서도 흐름을 직관적으로 파악 가능

결론: 타입스크립트에서의 안정적인 비동기 처리

TypeScript의 비동기 프로그래밍Promiseasync/await을 통해 직관적이고 안전한 코드를 작성할 수 있도록 도와줍니다. 특히 타입 명시와 에러 처리를 통해 런타임 오류를 줄이고, 안정적인 시스템을 구축하는 데 기여합니다.

실무 프로젝트에서는 응답 타입을 인터페이스로 정의하고, try/catch를 통한 예외 처리를 표준으로 삼는 것이 좋습니다. 또한 Promise.all과 같은 병렬 처리 기술도 성능 향상에 유리하게 작용합니다.