EventLoop, Task Queue

상민 상민

EventLoop, Task Queue

Event Loop

이벤트 루프는 자바스크립트 엔진이 아니라, 브라우저 혹은 노드에서 가지고 있다.

콜 스택과, 태스크 큐를 감시하여 콜 스택이 비어있으면 태스크 큐에 있는 콜백을 가져와 콜스택에 넣는다.

태스크큐를 자세하게 설명하면 마이크로 태스크 큐와 일반 태스크 큐로 나눌 수 있다.

여기서는 태스크 큐와 마이크로 태스크 큐의 차이에 대해 알아보자.

태스크 큐 vs 마이크로 태스크 큐

2개의 큐 모두 콜백함수가 들어간다.

콜백함수를 태스크 큐에 넣는 함수들

setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI 렌더링

콜백함수를 마이크로태스크 큐에 넣는 함수들

process.nextTick, Promise, Object.observe, MutationObserver

익숙한 함수인 Web API의 setTimeout() 의 콜백함수가 태스크 큐에 들어가고 Promise 의 콜백함수가 마이크로태스크 큐에 들어간다는 것을 알 수 있다. 이벤트 루프는 각 콜백함수를 태스크/마이크로태스크 큐에서 꺼내쓰는 것인데, 그렇다면 어떤게 먼저일까?

마이크로태스크가 더 우선순위가 높다

결론부터 말하자면, 마이크로태스크가 먼저이다.

1
2
3
4
5
6
7
8
9
10
function call() {
  console.log('콜 스택!');
  setTimeout(() => console.log('태스크 큐!'), 0);
  Promise.resolve().then(() => console.log('마이크로태스크 큐!'));
}

call();
// 콜 스택!
// 마이크로태스크 큐!
// 태스크 큐!

setTimeOutPromise의 위치를 바꾸어도 마이크로태스크가 먼저 출력이 된다.

process.nextTick

process.nextTick()이 기술적으로는 이벤트 루프의 일부가 아니다.

대신 nextTickQueue는 이벤트 루프의 현재 단계와 관계없이 현재 작업이 완료된 후에 처리한다.

여기에서 작업이란 기저의 C/C++ 핸들러에서 전환하는 것, 또 실행되어야 하는 JavaScript를 처리하는 것을 말한다.

해당 단계에서 process.nextTick()을 호출하면 process.nextTick()에 전달한 모든 콜백은 언제나 이벤트 루프를 계속 진행하기 전에 처리한다.

이 동작 때문에 재귀로 process.nextTick()을 호출하면 이벤트 루프가 poll 단계에 다다르는 것을 막아서 I/O가 starving 될 수 있으므로 좋지 않은 상황을 만들 수 있다.

setImmediate

process.nextTick() vs setImmediate()

개발자가 관심 가질 두 가지 유사한 호출이 있다.

process.nextTick()은 같은 단계에서 바로 실행된다. setImmediate()는 이어진 순회나 이벤트 루프의 ‘tick’에서 실행된다.

사실 이름은 서로 바뀌어야 한다. process.nextTick()setImmediate()보다 더 즉시 실행된다.

Summary

main.png

요약하면 위의 그림과 같다.

comments powered by Disqus