Search
🔄

아이템 25. 콜백 대신 async 사용 하기

Promise & Async/await은 callback 보다 코드 작성 및 타입 추론에 유리
Async/await은 promise 보다 직관적 & 간결 & 오류 제거
Promise 반환 함수는 async 선언이 유리

1. Promise & Async/await의 장점

콜백보다 코드 작성이 쉬움 + 타입 추론에 유리
// 병렬로 페이지 로드를 원할 시 Promise.All 사용해 구현 가능 // response* 변수의 타입을 response로 추론 async function fetchPages() { const [response1, response2, response3] = await Promise.all([fetch(url1), fetch(url2), fetch(url3)]) // ... } // 콜백 스타일로 작성하려면 구문 및 타입 코드가 늘어남 function fetchPagesCB() { let numDone = 0 const responses: string[] = [] const done = () => { const [response1, response2, response3] = responses // ... } const urls = [url1, url2, url3] urls.forEach((url, i) => { fetchURL(url, r => { responses[i] = url numDone++ if (numDone === urls.length) done() }) }) } // Promise.race도 타입 추론과 잘 맞음 // Promise.race: 병렬로 실행하되 가장 빨리 실행된 것만 resolve // timeout의 type은 never (return이 없거나 항상 오류 반환) function timeout(millis: number): Promise<never> { return new Promise((resolve, reject) => { setTimeout(() => reject('timeout'), millis) }) } async function fetchWithTimeout(url: string, ms: number) { return Promise.race([fetch(url), timeout(ms)]) }
TypeScript
복사

2. Async/await의 Promise 대비 장점

async는 항상 promise를 반환하도록 강제
// function getNumber(): Promise<number> async function getNumber() { return 42 } const getNumber = async () => 42 // Type is () => Promise<number> const getNumber = () => Promise.resolve(42) // Type is () => Promise<number>
TypeScript
복사
Promise 반환 강제는 함수의 통일성에 도움이 됨(동기/비동기 측면)
// 함수는 항상 동기 또는 비동기로 실행되어야 함 // 잘못된 예시 // 캐시되어 있다면 requestStatus는 success 이후에 loading으로 돌아감 const _cache: { [url: string]: string } = {} function fetchWithCache(url: string, callback: (text: string) => void) { if (url in _cache) { callback(_cache[url]) } else { fetchURL(url, text => { _cache[url] = text callback(text) }) } } let requestStatus: 'loading' | 'success' | 'error' function getUser(userId: string) { fetchWithCache(`/user/${userId}`, profile => { requestStatus = 'success' }) requestStatus = 'loading' } // async로 리팩토링 // 이제 requestedStatus가 success로 끝나는 것이 명백 async function fetchWithCache(url: string) { if (url in _cache) { return _cache[url] } const response = await fetch(url) const text = await response.text() _cache[url] = text return text } let requestStatus: 'loading' | 'success' | 'error' async function getUser(userId: string) { requestStatus = 'loading' const profile = await fetchWithCache(`/user/${userId}`) requestStatus = 'success' }
TypeScript
복사
async 함수에서 promise 반환 시 추가적인 promise로 래핑되지 않음
// Function getJSON(url: string): Promise<any> async function getJSON(url: string) { const response = await fetch(url) const jsonPromise = response.json() // Type is Promise<any> return jsonPromise }
TypeScript
복사