본문으로 건너뛰기
김신건의 로그

[Javascript] async/await

· 수정 · 📖 약 1분 · 359자/단어 #javascript #async #ecmascript #syntax-sugar
JS Async Await, async/await, async await, async-await, async function, 비동기 함수, JavaScript async/await, JS async/await

정의

async / awaitPromise 기반 비동기 코드를 마치 동기 코드처럼 쓸 수 있게 해주는 ES2017 의 문법 설탕. 본질은 Promise 그 자체, 문법만 다르다.

전체 동작 메커니즘은 비동기와 타이밍, 콜백부터 async/await까지의 발전사 글 참조.

세 가지 규칙

  1. async 함수는 항상 Promise 를 반환. return valuePromise.resolve(value) 와 같다.
  2. await exprexpr 이 정착할 때까지 함수 실행을 일시정지. 함수 밖 동기 코드는 계속 진행.
  3. 에러는 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);
}

엔진 안에서:

  1. 오른쪽 표현식을 평가, Promise 가 아니면 Promise.resolve 로 감쌈.
  2. 함수 상태를 Lexical Environment 에 저장.
  3. Promise 정착 시 Microtask Queue 에 “함수 재개” 등록.
  4. 마이크로태스크 차례가 오면 함수 이어 실행.

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) 에 도입되어 기반 비동기의 가독성과 에러 처리 문제를 해결했다. …

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기