비동기 프로그래밍이란?
비동기 프로그래밍은 코드가 실행되는 동안 시간이 걸리는 작업(예: 네트워크 요청, 파일 읽기 등)을 기다리지 않고, 다음 코드를 계속 실행하도록 하는 방식입니다. JavaScript와 TypeScript는 비동기 처리에 매우 최적화된 언어로, Promise와 async/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의 비동기 프로그래밍은 Promise와 async/await을 통해 직관적이고 안전한 코드를 작성할 수 있도록 도와줍니다. 특히 타입 명시와 에러 처리를 통해 런타임 오류를 줄이고, 안정적인 시스템을 구축하는 데 기여합니다.
실무 프로젝트에서는 응답 타입을 인터페이스로 정의하고, try/catch를 통한 예외 처리를 표준으로 삼는 것이 좋습니다. 또한 Promise.all과 같은 병렬 처리 기술도 성능 향상에 유리하게 작용합니다.