비동기
1. 비동기 처리
1.1 Promise와 async/await 타입 지정
TypeScript에서 비동기 작업을 처리할 때는 Promise 타입을 사용합니다. 특히 API 호출이나 파일 처리 같은 작업에서 자주 사용됩니다.
// 기본적인 Promise 타입 사용
interface User {
id: number;
name: string;
email: string;
}
// Promise를 반환하는 함수 정의
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// 실제 사용 예제
async function displayUserInfo(id: number): Promise<void> {
try {
const user = await fetchUser(id);
console.log(`${user.name}의 이메일: ${user.email}`);
} catch (error) {
console.error('사용자 정보를 가져오는데 실패했습니다.');
}
}
💡 async 함수는 자동으로 Promise를 반환합니다. 명시적인 타입 지정으로 코드의 의도를 더 명확하게 만들 수 있습니다.
1.2 Promise.all / Promise.allSettled 타입
여러 비동기 작업을 동시에 처리할 때 Promise.all이나 Promise.allSettled를 사용합니다. TypeScript는 각 Promise의 반환 타입을 튜플로 추론합니다.
Promise.all
모든 Promise가 성공해야 결과를 반환합니다. 하나라도 실패하면 전체가 실패합니다.
interface User {
id: number;
name: string;
}
interface Order {
id: number;
productName: string;
price: number;
}
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
async function fetchOrders(userId: number): Promise<Order[]> {
const response = await fetch(`/api/users/${userId}/orders`);
return response.json();
}
// Promise.all 사용 - 튜플 타입으로 추론됨
async function fetchUserWithOrders(userId: number): Promise<[User, Order[]]> {
const [user, orders] = await Promise.all([
fetchUser(userId),
fetchOrders(userId)
]);
return [user, orders];
}
// 사용 예제
async function displayUserDashboard(userId: number): Promise<void> {
const [user, orders] = await fetchUserWithOrders(userId);
console.log(`${user.name}님의 주문 내역: ${orders.length}건`);
}
Promise.allSettled
모든 Promise의 결과를 반환합니다. 성공/실패 여부와 관계없이 각 결과를 확인할 수 있습니다.
interface Product {
id: number;
name: string;
price: number;
}
async function fetchProduct(id: number): Promise<Product> {
const response = await fetch(`/api/products/${id}`);
if (!response.ok) {
throw new Error(`상품 ${id}를 찾을 수 없습니다.`);
}
return response.json();
}
// Promise.allSettled 사용
async function fetchMultipleProducts(ids: number[]): Promise<Product[]> {
const results = await Promise.allSettled(
ids.map(id => fetchProduct(id))
);
// 성공한 결과만 필터링
const products: Product[] = [];
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
products.push(result.value);
} else {
console.error(`상품 ID ${ids[index]} 조회 실패:`, result.reason);
}
});
return products;
}
💡 Promise.all은 빠른 실패(fail-fast) 전략이 필요할 때, Promise.allSettled는 일부 실패해도 나머지 결과가 필요할 때 사용합니다.
2. 연습문제
-
비동기 함수 타입 지정:
// TODO: 아래 함수의 반환 타입을 지정하고, // 적절한 인터페이스를 만드세요 async function fetchUserOrders(userId) { const response = await fetch(`/api/users/${userId}/orders`); return response.json(); } -
Promise.all 타입 지정:
// TODO: 아래 함수의 타입을 완성하세요 // 게시글과 댓글을 동시에 가져오는 함수입니다 async function fetchPostWithComments(postId) { const [post, comments] = await Promise.all([ fetch(`/api/posts/${postId}`).then(res => res.json()), fetch(`/api/posts/${postId}/comments`).then(res => res.json()) ]); return { post, comments }; }
3. 연습문제 해답
-
비동기 함수 해답:
interface Order { id: number; productId: number; quantity: number; totalPrice: number; } async function fetchUserOrders(userId: number): Promise<Order[]> { const response = await fetch(`/api/users/${userId}/orders`); return response.json(); } -
Promise.all 해답:
interface Post { id: number; title: string; content: string; authorId: number; } interface Comment { id: number; postId: number; text: string; authorName: string; } interface PostWithComments { post: Post; comments: Comment[]; } async function fetchPostWithComments(postId: number): Promise<PostWithComments> { const [post, comments] = await Promise.all([ fetch(`/api/posts/${postId}`).then(res => res.json()) as Promise<Post>, fetch(`/api/posts/${postId}/comments`).then(res => res.json()) as Promise<Comment[]> ]); return { post, comments }; }