[Javascript] async/await
JS Async Await, async/await, async await, async-await, async function, 비동기 함수, JavaScript async/await, JS async/await
정의
async / await 는 Promise 기반 비동기 코드를 마치 동기 코드처럼 쓸 수 있게 해주는 ES2017 의 문법 설탕. 본질은 Promise 그 자체, 문법만 다르다.
전체 동작 메커니즘은 비동기와 타이밍, 콜백부터 async/await까지의 발전사 글 참조.
세 가지 규칙
async함수는 항상 Promise 를 반환.return value는Promise.resolve(value)와 같다.await expr은expr이 정착할 때까지 함수 실행을 일시정지. 함수 밖 동기 코드는 계속 진행.- 에러는
try/catch로. Promise 의.catch와 동등.
async function loadProfile(userId) {
try {
const userRes = await fetch(`/users/${userId}`);
const user = await userRes.json();
const postsRes = await fetch(`/posts?u=${user.id}`);
return { user, posts: await postsRes.json() };
} catch (err) {
console.error(err);
throw err;
}
}
await 의 실제 동작
await 는 .then 의 문법 설탕이다.
// async/await
async function f() {
const a = await loadA();
return a + 1;
}
// 동치
function f() {
return loadA().then((a) => a + 1);
}
엔진 안에서:
- 오른쪽 표현식을 평가, Promise 가 아니면
Promise.resolve로 감쌈. - 함수 상태를 Lexical Environment 에 저장.
- Promise 정착 시 Microtask Queue 에 “함수 재개” 등록.
- 마이크로태스크 차례가 오면 함수 이어 실행.
IMPORTANT
await 이후 코드는 항상 다음 마이크로태스크 틱에 실행. 동기 코드보다 늦고, setTimeout 보다 빠르다.
함정
순차 vs 병렬
// 순차 (총 2초)
const a = await fetch('/a'); // 1초
const b = await fetch('/b'); // 1초
// 병렬 (총 1초)
const [a, b] = await Promise.all([fetch('/a'), fetch('/b')]);
의존성 없는 작업은 Promise.all 로 묶자.
반복문 안의 await
// 순차 처리 (의도적이라면 OK)
for (const id of ids) {
await process(id);
}
// 병렬 처리
await Promise.all(ids.map(process));
forEach 안의 await 는 동작 안 함
// ❌ forEach 는 async 콜백을 기다리지 않음
ids.forEach(async (id) => await process(id));
console.log('done'); // 아직 process 들이 도는 중에 출력
// ✅ for-of 또는 Promise.all
for (const id of ids) await process(id);
// 또는
await Promise.all(ids.map(process));
Top-level await
ES2022 부터 ES Module 최상위에서 await 가능.
// app.mjs
const config = await fetch('/config.json').then(r => r.json());
// 이후 코드는 config 가 로드된 후 실행
CommonJS 모듈에서는 불가.
참고
이 글의 용어 (4개)
- [Javascript] 이벤트 루프javascript
- 정의 이벤트 루프 (Event Loop) 는 싱글 스레드 JavaScript 엔진이 비동기 작업을 처리하기 위해 돌리는 무한 루프다. 콜 스택이 비어있을 때마다 마이크로태스크 큐…
- [Javascript] Lexical Environmentjavascript
- 정의 Lexical Environment (어휘적 환경) 는 ECMAScript 명세 (§9.1) 가 정의한 내부 객체. 함수가 호출될 때마다 새로 만들어지며, 이 호출의 변수들…
- [Javascript] Microtask Queuejavascript
- 정의 Microtask Queue (마이크로태스크 큐) 는 JavaScript 가 매 틱마다 완전히 비울 때까지 처리하는 우선순위 큐다. 매크로태스크 큐보다 항상 먼저 비워진다.…
- [Javascript] Promisejavascript
- 정의 Promise 는 미래의 어떤 시점에 결정될 값을 나타내는 객체다. ECMAScript 2015 (ES6) 에 도입되어 기반 비동기의 가독성과 에러 처리 문제를 해결했다. …
이 개념을 다룬 위키 페이지 (13)
- wikiAsynchronous (비동기)
- wiki[Frontend] React 19.x: Actions, Activity, RSC, Foundation
- wiki[React] useEffect: 동기화의 본질, dep array, cleanup, useEffectEvent
- wiki[JavaScript] AbortController: 비동기 취소
- wiki[Javascript] 콜백 지옥
- wiki[Javascript] Error / try-catch
- wiki[Javascript] 이벤트 루프
- wiki[Javascript] 함수의 종류
- wiki[Javascript] Iterator / Generator
- wiki[Javascript] Microtask Queue
- wiki[Javascript] Promise
- wiki[Javascript] Promise.all / race / any / allSettled
- wiki[Python] asyncio: 비동기 프로그래밍
💬 댓글