스택과 분리하여 이벤트 루프에 대해 논의 할 수 없다고 생각합니다.
JS에는 세 개의 "스택"이 있습니다.
- 모든 동기 호출에 대한 표준 스택 (한 함수가 다른 함수를 호출하는 등)
- 우선 순위가 높은 모든 비동기 작업 (process.nextTick, Promises, Object.observe, MutationObserver)에 대한 마이크로 태스크 대기열 (또는 작업 큐 또는 마이크로 태스크 스택 )
- 우선 순위가 낮은 모든 비동기 작업 (setTimeout, setInterval, setImmediate, requestAnimationFrame, I / O, UI 렌더링)에 대한 매크로 작업 대기열 (또는 이벤트 대기열, 작업 대기열, 매크로 작업 대기열 )
|=======|
| macro |
| [...] |
| |
|=======|
| micro |
| [...] |
| |
|=======|
| stack |
| [...] |
| |
|=======|
그리고 이벤트 루프는 다음과 같이 작동합니다.
- 스택에서 맨 아래부터 맨 위까지 모든 것을 실행하고 스택이 비어있을 때만 위의 대기열에서 무슨 일이 일어나고 있는지 확인하십시오.
- 마이크로 스택을 확인하고 스택의 도움으로 모든 작업을 실행하십시오 (필요한 경우). 마이크로 작업 대기열이 비어 있거나 실행이 필요하지 않을 때까지 한 번에 한 번의 작업으로 매크로 스택을 확인하십시오.
- 매크로 스택을 확인하고 스택의 도움으로 필요한 경우 모든 것을 실행하십시오.
스택이 비어 있지 않으면 Mico 스택이 닿지 않습니다. 마이크로 스택이 비어 있지 않거나 실행이 필요하지 않으면 매크로 스택은 건드리지 않습니다.
요약하자면, 마이크로 태스킹 큐는 매크로 태스크 큐와 거의 동일하지만 해당 태스크 (process.nextTick, Promises, Object.observe, MutationObserver) 는 매크로 태스크 보다 우선 순위가 높습니다.
마이크로는 매크로와 비슷하지만 우선 순위가 높습니다.
여기에 모든 것을 이해하기위한 "궁극적 인"코드가 있습니다.
console.log('stack [1]');
setTimeout(() => console.log("macro [2]"), 0);
setTimeout(() => console.log("macro [3]"), 1);
const p = Promise.resolve();
for(let i = 0; i < 3; i++) p.then(() => {
setTimeout(() => {
console.log('stack [4]')
setTimeout(() => console.log("macro [5]"), 0);
p.then(() => console.log('micro [6]'));
}, 0);
console.log("stack [7]");
});
console.log("macro [8]");
/* Result:
stack [1]
macro [8]
stack [7], stack [7], stack [7]
macro [2]
macro [3]
stack [4]
micro [6]
stack [4]
micro [6]
stack [4]
micro [6]
macro [5], macro [5], macro [5]
--------------------
but in node in versions < 11 (older versions) you will get something different
stack [1]
macro [8]
stack [7], stack [7], stack [7]
macro [2]
macro [3]
stack [4], stack [4], stack [4]
micro [6], micro [6], micro [6]
macro [5], macro [5], macro [5]
more info: https://blog.insiderattack.net/new-changes-to-timers-and-microtasks-from-node-v11-0-0-and-above-68d112743eb3
*/
while (task = todo.shift()) task();