서론
자바스크립트를 공부하다가 setTimeout, Promise, fetch 같은 비동기 함수들이 어떻게 작동하는지 궁금해졌습니다. 자바스크립트는 싱글 스레드 기반의 언어이기 때문에 기본적으로는 한 번에 한 작업만 처리할 수 있어야 합니다. 하지만 실제로는 여러 비동기 작업들이 동시에 처리되는 것처럼 동작합니다.
"어떻게 이런 일이 가능할까요?"
이 의문에 대한 해답이 바로 이벤트 루프(Event Loop)입니다.
이번 글에서는 이벤트 루프의 개념과 동작 원리, 그리고 setTimeout과 Promise를 예시로 들어 비동기 코드가 어떻게 처리되는지 구체적으로 살펴보겠습니다.
이벤트 루프란?
자바스크립트는 기본적으로 싱글 스레드(single-thread) 언어입니다.
즉, 한 번에 하나의 작업만 실행할 수 있습니다.
그런데 우리는 자바스크립트로
setTimeout 같은 비동기 함수
Promise
fetch 같은 비동기 I/O 요청
사용자 이벤트 처리
등을 자유롭게 사용합니다.
🤔 어떻게 동시적으로 처리할 수 있는 것처럼 보일까요?
바로 이벤트 루프(Event Loop) 덕분입니다.
이벤트 루프의 기본 구성 요소
자바스크립트의 비동기 처리는 이벤트 루프가 중심이 되어 아래 3가지 요소가 협력합니다.
구성 요소 설명
Call Stack (콜 스택) | 현재 실행 중인 함수들의 스택 |
Web API (브라우저 또는 Node API) | 비동기 작업 처리 (타이머, 이벤트, AJAX 등) |
Task Queue (태스크 큐) | 완료된 비동기 콜백이 대기하는 큐 (매크로/마이크로로 나뉨) |
예시
setTimeout(callback, 0) 은 즉시 실행되지 않는다.
console.log('1');
setTimeout(() => {
console.log('2');
}, 0);
console.log('3');
실행 결과
1
3
2
왜 그럴까?
- console.log('1') → 즉시 실행
- setTimeout(...) → Web API에 위임, 타이머(0ms) 시작
- console.log('3') → 즉시 실행
- 콜 스택이 비게 되면
→ 이벤트 루프가 태스크 큐(Task Queue) 에서 대기 중인 콜백 꺼내 실행
✅ 0ms는 “즉시 실행”이 아니라
→ “다음 이벤트 루프 사이클에 실행해줘”라는 의미입니다.
이벤트 루프 흐름 정리
1. Call Stack이 비어있는지 확인
2. Microtask Queue가 비어있지 않다면 → 모두 처리
3. 그 후 Macrotask Queue에서 하나 꺼내 실행
4. 1번으로 다시 반복
태스크 큐 종류
1) 매크로태스크 큐 (Macrotask Queue)
일반적인 비동기 작업이 들어가는 큐
예시
- setTimeout(),
- setInterval(),
- setImmediate() (Node.js),
- MessageChannel
2) 마이크로태스크 큐 (Microtask Queue)
더 빠르게, 더 우선적으로 처리해야 할 작업이 들어감
예시
- Promise.then(),
- catch(),
- finally()
- queueMicrotask()
마이크로 vs 매크로 우선순위
항상 마이크로태스크 큐가 먼저 처리됩니다!
console.log('start');
setTimeout(() => {
console.log('Macrotask: setTimeout');
}, 0);
Promise.resolve().then(() => {
console.log('Microtask: Promise');
});
console.log('end');
실행 결과
start
end
Microtask: Promise
Macrotask: setTimeout
setTimeout 루프 예제로 이벤트 루프 작동 방식을 알아봅시다!
💬 setTimeout을 통한 비동기 작업 흐름 + DOM 조작을 통한 시각적 확인 가능
See the Pen Untitled by Sonne (@Dubabbi) on CodePen.
위의 예제에는 두 개의 버튼이 있습니다.
첫 번째 버튼은 동기 실행 버튼으로, 클릭하면 곧바로 DOM에 "동기 작업 실행"이라는 문장이 출력됩니다. 이 작업은 자바스크립트의 동기적 실행 흐름에 따라 즉시 처리됩니다. 콜 스택에 함수가 쌓이고 바로 실행되기 때문에, 버튼을 누르는 즉시 결과가 나타나는 것입니다.
두 번째 버튼은 setTimeout 루프 시작입니다. 이 버튼을 클릭하면 setTimeout(..., 0)을 사용하는 재귀 루프 함수가 실행됩니다. 이 setTimeout 호출은 Web API에 위임되며, 최소 대기 시간이 지난 후 콜백 함수가 Task Queue에 등록됩니다. 이후 이벤트 루프는 콜 스택이 비어 있는지 확인한 뒤, Task Queue에 쌓인 콜백을 꺼내 실행합니다. 콜백 내부에서는 다시 loop() 함수가 호출되어, 이 동작이 비동기적으로 반복되며 "setTimeout으로 실행된 비동기 작업"이라는 문장이 loopArea에 계속 출력됩니다.
중요한 점은 setTimeout(..., 0)이라 해도 즉시 실행되는 것이 아니라, 현재 실행 중인 모든 동기 작업이 완료된 후에 실행된다는 것입니다. 이를 통해 이벤트 루프가 콜 스택이 비워진 상태에서만 태스크 큐의 작업을 실행한다는 원리를 확인할 수 있습니다. 실제로 두 버튼을 모두 클릭해보면, 동기 실행 버튼의 출력 결과가 setTimeout으로 출력되는 비동기 메시지보다 항상 먼저 표시되는 것을 볼 수 있습니다.
이는 자바스크립트의 이벤트 루프가 동기 작업이 우선이며, 비동기 콜백은 항상 다음 이벤트 루프 사이클에서 처리된다는 규칙을 잘 보여줍니다.
결론
이벤트 루프는 자바스크립트에서 비동기 처리를 가능하게 해주는 핵심 메커니즘으로, 콜 스택, 웹 API, 태스크 큐(매크로/마이크로)와의 협업을 통해 동기와 비동기 작업을 효율적으로 처리합니다.
특히 Promise나 setTimeout의 실행 순서 차이를 이해하면
실제 개발에서도 예상치 못한 비동기 실행 오류를 방지하는 데 큰 도움이 됩니다.
자바스크립트의 비동기 처리 흐름을 제대로 이해하고 싶다면
이벤트 루프는 반드시 정확히 짚고 넘어가야 할 개념이라고 합니다!
'1주차' 카테고리의 다른 글
웹 스토리지 (Web Storage) (0) | 2025.04.11 |
---|---|
🧐 브라우저에 www.google.com을 입력하면 어떤 일이 일어날까? (0) | 2025.04.10 |
웹접근성과 웹 표준 [시맨틱 태그, SEO] (0) | 2025.04.10 |
웹 브라우저의 작동 원리 (0) | 2025.04.09 |
🔍앵커 기반 스크롤의 주소 문제 해결하기 (0) | 2025.04.09 |