일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- python
- 타임어택
- 렛츠기릿 자바스크립트
- 제로초
- 코드스테이츠
- programmers
- 프로그래머스
- 백준
- 타입스크립트 올인원
- 2주 프로젝트
- codestates
- 4주 프로젝트
- 리트코드
- 리액트
- 회고
- 타입스크립트
- HTTP
- 파이썬
- 알고리즘
- SQL 고득점 Kit
- 리덕스
- js
- til
- javascript
- 토익
- 정재남
- 코어 자바스크립트
- 자바스크립트
- LeetCode
- 손에 익히며 배우는 네트워크 첫걸음
- Today
- Total
Jerry
#12. 마이크로태스크 큐 vs 태스크 큐 본문
자바스크립트의 비동기 처리 방식과 이벤트 루프의 동작 원리를 이해하기 위해서는
마이크로태스크 큐(Microtask Queue)와 태스크 큐(Task Queue, 또는 Callback Queue)의 차이를
명확하게 이해하는 것이 중요합니다!
앞서, 아래와 같이 자바스크립트에 대해 표현했습니다.
JavaScript는 싱글 스레드(Single-threaded) 기반의 논 블로킹(Non-blocking) 언어로,
이벤트 기반(Event-driven), 비동기 처리(Asynchronous processing), 동시성(Concurrency)을 지원하는 동적 프로그래밍 언어
자바스크립트는 싱글 스레드 기반의 비동기 이벤트 처리 모델을 사용하는데, 이 모델에서 비동기 코드의 실행 순서를 결정하는 핵심 메커니즘이 이벤트 루프입니다. 이벤트 루프는 콜 스택과 태스크 큐(=콜백 큐), 마이크로태스크 큐를 이용하여 비동기 작업을 적절한 순서로 실행합니다.
콜 스택
- 자바스크립트가 함수를 실행할 때 사용하는 데이터 구조로, LIFO 방식으로 동작
태스크 큐
- 매크로태스크 큐라고도 불리며,
- setTimeout, setInterval, setImmediate(Node.js), I/O 작업, UI 렌더링 관련 작업과 같은
- 비동기 API의 콜백을 저장하는 큐
동작원리
- 콜 스택이 비어 있을 때, 이벤트 루프는 태스크 큐에서 가장 먼저 들어온 태스크를 가져와 실행 (FIFO)
- 태스크 실행되면, 해당 작업이 콜 스택에서 처리된 후 제거됨
- 새로운 태스크 발생 시, 다시 태스크 큐에 추가되고, 위 과정을 반복함
예제
console.log("Start");
setTimeout(() => {
console.log("Timeout Callback");
}, 0);
console.log("End");
setTimeout의 콜백 함수는 태스크 큐에 들어가고, 현재 실행 중인 동기 코드가 모두 실행된 후 실행됨.
Start
End
Timeout Callback
마이크로태스크 큐
- Promise의 .then(), MutationObserver, queueMicrotask() 등의 비동기 작업을 저장하는 큐
동작원리
- 콜 스택이 비어 있을 때마다, 태스크 큐보다 먼저 실행
- 마이크로태스크가 있으면, 이벤트 루프는 태스크 큐의 작업을 실행하기 전에 마이크로태스크를 모두 처리
- 새로운 마이크로태스크가 실행 중에 추가되면, 다시 그 마이크로태스크를 먼저 실행(Starvation 가능성 있음)
Starvation
- 마이크로태스크가 항상 태스크 큐보다 먼저 실행되며, 새로운 마이크로태스크가 생성되면 계속 우선 처리
- 따라서 마이크로태스크가 과도하게 생성되면 태스크 큐의 작업이 실행되지 못하는 Starvation(기아) 현상이 발생할 수도 있음
해결 방법
- 태스크 에 강제적으로 실행 기회 부여
- 마이크로태스크 실행 횟수 제한
예제
console.log("Start");
setTimeout(() => {
console.log("Timeout Callback");
}, 0);
Promise.resolve().then(() => {
console.log("Promise Callback");
});
console.log("End");
"Start" → 콜 스택에서 실행됨.
setTimeout → 태스크 큐에 콜백을 등록.
Promise.resolve().then(...) → 마이크로태스크 큐에 콜백을 등록.
"End" → 콜 스택에서 실행됨.
마이크로태스크 실행: "Promise Callback"
태스크 큐 실행: "Timeout Callback"
Start
End
Promise Callback
Timeout Callback
문제: 마이크로태스크가 계속 실행되면 태스크 큐 실행 불가능
- 만약 마이크로태스크가 계속 추가되면 태스크 큐에 있는 setTimeout(fn, 0) 같은 작업이 절대 실행되지 않음.
function repeatMicrotask() {
Promise.resolve().then(() => {
console.log("Microtask executed");
repeatMicrotask(); // 계속 마이크로태스크 추가
});
}
setTimeout(() => {
console.log("Task Queue Executed");
}, 0);
repeatMicrotask();
Microtask executed
Microtask executed
Microtask executed
...(무한 반복)
- repeatMicrotask()가 계속 Promise.resolve().then()을 실행하며 마이크로태스크를 무한히 추가
- 마이크로태스크가 끝나야 태스크 큐가 실행되는데, 마이크로태스크가 계속 추가되므로 태스크 큐가 실행되지 않음
- 따라서 setTimeout(fn, 0)이 실행될 기회를 얻지 못함.
마이크로태스크 vs 태스크 큐 정리
실행 순서 | 콜 스택이 비면 즉시 실행 | 마이크로태스크가 끝난 후 실행 |
대표 예제 | Promise.then(), MutationObserver, queueMicrotask() | setTimeout(), setInterval(), setImmediate(), I/O 작업 |
실행 시점 | 이벤트 루프가 다음 태스크를 실행하기 전에 모든 마이크로태스크를 먼저 처리 | 이벤트 루프의 한 사이클에서 실행됨 |
우선순위 | 매우 높음 | 상대적으로 낮음 |
부작용 | 무한 마이크로태스크 실행 가능 (Starvation 위험) | 실행 순서가 예상 가능 |
Q. 태스크 큐와 마이크로태스크 큐의 차이를 설명해 주세요
A. 자바스크립트의 이벤트 루프에서 비동기 처리는 두 가지 큐를 사용합니다.
태스크 큐와 마이크로태스크 큐가 있는데요.
먼저, 태스크 큐는 setTimeout, setInterval, setImmediate, I/O 작업과 같은 매크로 태스를 저장하며, 이벤트 루프 한 사이클이 끝날때마다 실행됩니다.
마이크로태스크 큐는 Promise.then, MutationObserver, queueMicrotask 같은 비동기 작업을 저장하며, 콜 스택이 비는 즉시 실행됩니다.
마이크로태스크 큐가 항상 태스크 큐보다 먼저 실행되며, 새로운 마이크로태스크 큐가 생성되면 계속 우선 처리됩니다. 따라서 마이크로태스크 큐가 과도하게 생성되 경우, 태스크 큐 작업 실행을 못하게 되는 Starvation(기아) 현상이 발생할 수도 있습니다.
Q. 다음 코드의 실행 순서를 예측해 보세요.
console.log("A");
setTimeout(() => {
console.log("B");
}, 0);
Promise.resolve().then(() => {
console.log("C");
});
console.log("D");
A. 출력 순서: A -> D -> C -> B 순으로 실행됩니다.
- 먼저, A가 콜 스택에 추가 및 실행되며,
- 다음으로 setTimeout 콜백이 태스크 큐에 등록
- Promise.then의 콜백이 마이크로태스크 큐에 등록
- D가 콜 스택에 추가 및 실행되며,
- 마이크로태스크 큐 실행하여 C가 실행
- B가 태스크 큐 실행
마이크로태스크 큐가 항상 태스크 큐보다 먼저 실행되는 원리를 알고 있어야 실행 순서에 대해 알 수 있는 문제입니다.
Q. 다음 코드의 실행 순서를 예측해 보세요.
Node.js에서는 process.nextTick()이 마이크로태스크보다도 먼저 실행됩니다.
console.log("Start");
setTimeout(() => {
console.log("Task Queue");
}, 0);
Promise.resolve().then(() => {
console.log("Microtask");
});
process.nextTick(() => {
console.log("Next Tick");
});
console.log("End");
'CS > Terminology' 카테고리의 다른 글
#11. JavaScript는 어떤 언어일까? (0) | 2025.03.15 |
---|---|
#10. LocalStorage vs SessionStorage vs Cookie (0) | 2025.03.13 |
#9. this 용법 (0) | 2025.03.11 |
#8. SSR vs CSR (0) | 2025.03.10 |
#7. 호이스팅, 전역 컨텍스트, 클로저 (2) | 2025.03.06 |