1. 이벤트 루프
이벤트 루프(브라우저에 내장되어 있는 기능)는 자바스크립트의 비동기 처리 메커니즘을 관리하는 핵심 엔진으로,
실행 컨텍스트가 담긴 콜 스택(Call Stack) 과, 나중에 실행될 (매크로) 태스크 큐(task Queue) 및 마이크로태스크 큐(Microtask Queue) 를 조율하는 역할을 한다.
자바스크립트는 단일 스레드 언어이기 때문에, 한 번에 하나의 작업만 수행할 수 있는데, 실행할 함수가 생기면 콜 스택에 쌓이고, 스택의 맨 위에 있는 함수부터 순차적으로 실행되는 것이다. 이때 비동기 작업(예: setTimeout, fetch)은 바로 실행되지 않고, 백그라운드에서 완료된 후 해당 콜백이 큐(매크로 또는 마이크로 태스크큐)에 등록된다.
이벤트 루프는 콜 스택이 비어 있는지 계속 감시하고 있다가, 콜 스택이 완전히 비면, 먼저 마이크로태스크 큐(Microtask Queue) (예: Promise.then, MutationObserver)의 콜백들을 모두 콜스택에 옮겨 실행하고, 그다음 태스크 큐(Task Queue) (예: setTimeout, setInterval, I/O)에 있는 콜백을 하나씩 스택으로 옮겨 실행한다.
이 과정을 반복하면서 자바스크립트는 동기적 실행 흐름 속에서도 비동기 작업을 자연스럽게 처리할 수 있는 것이다.
2. 실행 순서
실행 순서(우선순위)를 간략히 정리하면,
- 콜 스택 - 쌓여있는 동기 코드 실행
- 마이크로 태스크큐 - 우선순위가 태스크큐보다 더 높다. 모든 microtask를 한 번에 비울 때까지 실행
- Promise 의 .then, .catch, .finally 콜백
- queueMicrotask
- MutationObserver 콜백
- (Node.js) process.nextTick (Node 전용이지만 microtask처럼 동작)
- (매크로) 태스크큐 - 하나 꺼내어 콜스택에 넣고 실행
- setTimeout, setInterval
- setImmediate (Node.js)
- 브라우저의 requestAnimationFrame
- I/O callbacks (DOM 이벤트 핸들러, network 등)
왜 다르게 동작할까?
- 비동기 우선순위를 세분화하기 위해서이다.
- Promise 같은 언어 차원의 기본 비동기는 “다음 틱에서 바로 실행되길” 원하는 경우가 많음 → microtask
- 타이머나 DOM 이벤트처럼 환경(브라우저/Node)에서 발생하는 작업은 렌더링이나 사용자 상호작용 후에 처리해도 되므로 → macro task
3. 예제: 여러 매크로태스크 + 중첩 마이크로태스크
console.log('Start');
setTimeout(() => {
console.log('setTimeout 1');
Promise.resolve().then(() => {
console.log('Promise in setTimeout 1');
});
}, 0);
setTimeout(() => {
console.log('setTimeout 2');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 1');
setTimeout(() => {
console.log('setTimeout in Promise 1');
}, 0);
});
console.log('End');
1. 출력 순서
Start
End
Promise 1 // micro task queue
setTimeout 1 // macro
Promise in setTimeout 1 // micro
setTimeout 2 // macro
setTimeout in Promise 1 // macro
2. 설명
- Promise 1 은 마이크로태스크이므로 가장 먼저 실행됨.
- Promise 1 내부의 setTimeout 은 새로운 매크로태스크로 등록되어 뒤로 밀림.
- setTimeout 1 → Promise in setTimeout 1 → setTimeout 2 → setTimeout in Promise 1 순으로 실행된다.
4. 요약 포인트
구분 | 설명 |
콜 스택 | 실행 중인 함수가 올라가는 곳 |
마이크로태스크 큐 | Promise.then, queueMicrotask, MutationObserver 등 |
매크로태스크 큐 | setTimeout, setInterval, fetch, I/O 등 |
실행 순서 규칙 | 콜스택 비면 → 마이크로태스크 전부 실행 → 매크로태스크 하나 실행 → 반복 |