PracticeEveryday
Nodejs 본문
nextTickQueue , microTaskQueue
- nextTickQueue와 microTaskQueue는 앞에서 말했듯 이벤트 루프의 일부가 아니다.
- 정확히는 libUv에 포함되어 있지 않고 Node.js에 구현되어 있다. 따라서 이벤트 루프의 페이즈와 상관없이 동작한다.
nextTickQueue
nextTickQueue는 microTaskQueue 보다 높은 우선순위를 가지므로 더 먼저 실행된다.
Promise.resolve().then(() => console.log("resolve"));
process.nextTick(() => console.log("nextTick"));
// process.nextTick은 같은 페이즈에서 호출한 즉시 실행된다.
// nextTick
// resolve
- 다른 페이즈들과 다르게 nextTickQueue와 microTaskQueue는 시스템의 실행 한도의 영향을 받지 않는다.
- 따라서 Node.js는 큐가 비워질 때까지 콜백들을 실행한다.
const fn = () => {
process.nextTick(fn);
};
setTimeout(() => {
console.log("Timer");
}, 0);
fn();
// 영원히 Timer는 출력 되지 않는다.
nextTickQueue와 microTaskQueue의 동작변화
위 그림은 아래의 코드와 같다.
setTimeout(() => {
console.log(1);
process.nextTick(() => {
console.log(3);
});
Promise.resolve().then(() => console.log(4));
}, 0);
setTimeout(() => {
console.log(2);
}, 0);
1
3
4
2
// Node 11 버전 이전
// 한 페이즈에서 다음 페이즈로 넘어가기 전에 nextTickQueue와 microTaskQueue를 검사했다.
// 매 틱마다 검사를 했다!
Node.js가 Timer Phase에 진입
우선 Timer Phase에 있는 큐를 확인하고 console.log(1) 실행
process.nextTick과 Promise.resolve를 호출해 nextTickQueue와 microTaskQueue에 콜백을 등록
Node.js는 다시 Timer Phase에 있는 큐를 확인하고 console.log(2)를 실행
Node.js는 다시 Timer Phase에 있는 큐를 확인하고 비어있으므로 다음 페이즈로 넘어가려 함
Pending Callbacks Phase에 진입하기 전 우선순위가 높은 nextTickQueue부터 확인
console.log(3) 실행
nextTickQueue가 비었음을 확인하고 우선순위가 낮은 microTaskQueue 확인
console.log(4) 실행
microTaskQueue가 비었음을 확인하고 Pending Callbacks Phase로 이동
// Node 11 버전 이후
// 현재 실행하고 있는 작업이 끝나면 즉시 실행하도록 변경 되었다.
Node.js가 Timer Phase에 진입
우선 Timer Phase에 있는 큐를 확인하고 console.log(1) 실행
process.nextTick과 Promise.resolve를 호출해 nextTickQueue와 microTaskQueue에 콜백을 등록
현재 실행하고 있는 작업이 끝났으므로 Node.js는 nextTickQueue와 microTaskQueue에 작업이 있음을 확인
-> Timer Phase의 큐를 확인하지 않고 우선순위가 높은 nextTickQueue 부터 확인
console.log(3) 출력
Node.js는 nextTickQueue가 비었음을 확인하고 우선순위가 낮은 microTaskQueue 확인
console.log(4) 출력
microTaskQueue가 비었음을 확인하고 다시 Node.js는 Timer Phase에 있는 큐를 확인하고 console.log(2) 실핼
현재 실행하고 있는 작업이 끝났으므로 Node.js는 nextTickQueue와 microTaskQueue에 작업이 있음을 확인
-> Timer Phase의 큐가 비었음을 확인하고 Pending Callbacks Phase로 이동
Node v10.0.0에서는 한 페이즈에서 다음 페이즈로 넘어갈 때 nextTickQueue와 microTaskQueue를 검사한다. 즉, 위 예제에서는 Timer Phase의 콜백 2개를 실행하고 나서야 nextTickQueue에 있는 콜백을 실행할 수 있다. 따라서 setTimeout의 콜백들이 모두 실행되고 나서 process.nextTick의 콜백들이 실행된다.
하지만 Node v11.0.0에서는 현재 실행하고 있는 작업이 끝나면 즉시 큐를 검사하고 실행한다. 따라서 Node v10.0.0과는 달리 setTimeout의 콜백을 먼저 하나 실행하고 그 즉시, process.nextTick의 콜백을 실행한다. 따라서 3보다 2가 먼저 출력된다.
Node v11.0.0에서 실행 순서가 바뀌게 된 이유는 바로 브라우저와의 일관성때문이다. Node.js는 브라우저에서 실행하던 Javascript를 로컬에서 실행하게 해주는 런타임이다. 그러나 브라우저는 Node v11.0.0의 실행 순서를 따르고 있었기에 같은 자바스크립트 코드더라도 Node v10과 브라우저의 실행 결과가 동일하지 않았다.
이러한 문제를 해소하기 위해서 Node v11.0.0에서는 브라우저와 같은 실행 순서를 가지도록 변경되었다.
Node.js 이벤트 루프(Event Loop) 샅샅이 분석하기
글에 들어가기에 앞서 Node.js의 이벤트 루프의 경우 공식 문서에 설명이 부족하고 이에 따라 여러 사람들이 각자 나름대로 분석한 글이 많아 무엇이 이벤트 루프의 정확한 동작인지 알기 힘듭니
www.korecmblog.com