마이크로태스크란

  • 지금 실행 중인 코드가 끝나자마자, 브라우저가 다른 일(렌더링·다음 이벤트)을 하기 전에 먼저 처리되는 짧은 작업 큐
  • 만드는 것: Promise .then/.catch/.finally, await 이후 코드, queueMicrotask(), MutationObserver

이벤트 루프 순서

① 매크로태스크 하나 실행 (예: 현재 스크립트)
② 마이크로태스크 큐를 전부 비움
③ (필요하면) 렌더링
④ 다음 매크로태스크 하나 실행
→ 반복

"매크로 하나 → 마이크로 전부 → 렌더 → 매크로 하나" 리듬이다.

매크로 vs 마이크로

매크로태스크마이크로태스크
예시setTimeout, setInterval, 이벤트 핸들러, I/OPromise 콜백, await 이후, queueMicrotask
실행한 번에 하나씩현재 코드 직후 큐를 몽땅
렌더 전 처리아니오예 (렌더보다 먼저 다 비움)

출력 순서

console.log("1");
setTimeout(() => console.log("2"), 0);          // 매크로
Promise.resolve().then(() => console.log("3")); // 마이크로
console.log("4");

// 출력: 1 → 4 → 3 → 2

동기 코드(1, 4) → 마이크로 비움(3) → 다음 매크로(2). setTimeout(0)이라도 마이크로가 항상 먼저다.

await는 마이크로태스크다

async function f() {
  console.log("a");
  await something; // 여기서 함수가 잠깐 멈춤
  console.log("b"); // await 이후는 마이크로태스크로 예약됨
}

await는 문법 설탕이고, 뒷부분(b)이 .then 콜백처럼 마이크로태스크 큐에 들어가 실행된다.

함정 — 마이크로태스크 기아(starvation)

마이크로 큐는 전부 비울 때까지 다음 단계로 안 넘어간다. 마이크로 안에서 또 마이크로를 계속 만들면 렌더링·매크로가 실행되지 못한다.

function loop() {
  Promise.resolve().then(loop); // 무한히 마이크로 재생성
}
loop();
// → 렌더링·setTimeout이 영영 실행 못 됨 (브라우저 멈춤)

무거운 반복 작업은 매크로(setTimeout)로 쪼개야 한다.

queueMicrotask

  • "동기 코드 직후, 렌더 전에" 실행하고 싶을 때. Promise를 만들지 않고 마이크로태스크만 예약하는 방법
queueMicrotask(() => console.log("동기 코드 직후 실행"));

정리

  • 마이크로태스크 = Promise/await가 만드는, 현재 코드 직후 렌더보다 먼저 몰아서 처리되는 우선 큐
  • 매크로태스크(setTimeout 등)보다 항상 먼저이고, 큐를 완전히 비운 뒤에야 다음 단계로 넘어간다