Javascript - Microtask

마이크로태스크

비동기 작업을 처리하기 위해서는 해당 비동기 작업들을 자바스크립트 엔진은 내부적으로 어떤 큐에 집어넣는다. 그 큐를 V8에서는 마이크로태스크 큐라고 부른다.

명세서에서는 마이크로태스크 큐는 큐의 특성에 맞게 선입선출 작업으로 실행한다. 그리고 실행할 것이 없을 때 마이크로태스크 큐에 있는 작업들이 실행된다라고 설명되어있다.

즉, 비동기작업은 어떤 동기적인 작업이 모두 끝난 후 실행되는데, 그렇게 동작하기 위해 있는 것이 마이크로태스크 큐이다.

이벤트 루프

마이크로태스크 큐를 깊이 공부해보려면, 우선 이벤트 루프를 다시 짚고 가야할 것이다. 자바스크립트는 단일 스레드 기반의 언어이다. 스레드가 하나라는 것은 하나의 작업만을 처리할 수 있다는 것이다. 여기서 자바스크립트는 어떻게 동시성을 지원할까? 이것이 이벤트 루프가 존재하는 이유이다.

자바스크립트는 이벤트 루프를 이용하여 비동기 방식으로 동시성을 지원한다. 이 동시성에 대한 처리는 자바스크립트 엔진을 구동하는 브라우저나 Node.js가 담당하게 된다.

이벤트 루프에 대한 자세한 설명은 이전에도 같은 링크를 보고 정리한 적이 있어 내 블로그 링크로 대체한다.

이벤트 루프

마이크로태스크 큐

이벤트 루프에서는 태스크 큐라는 것이 있는데, 이 태스크 큐는 하나의 큐가 아닌 여러종류의 큐가 있다고 한다. 정확히 어떤 종류의 큐들이 있는지는 각각 지원해주는 환경마다 다를 것이다.

확실한 것은, V8에서는 마이크로태스크 큐와 그냥 일반 태스크 큐가 구분되어 있는데, 마이크로태스크가 일반 태스크보다 더 높은 우선 순위를 갖는다. 즉, 태스크보다 마이크로테스크가 더 먼저 실행된다는 것이다.

어떤 비동기 Web API 코드가 있고, 프로미스 코드가 있을 때, Web API는 일반 테스크 큐에 추가되고, 프로미스는 마이크로테스크 큐에 추가되게 된다. 그리고 동기적인 코드의 흐름이 끝난 후 이벤트 루프는 마이크로테스크 큐를 먼저 확인하여 코드를 실행시키고, 그 다음에 테스크 큐를 확인하여 Web API 코드를 실행시키게 된다.

setTimeout(function() { // (A)
    console.log('A');
}, 0);
Promise.resolve().then(function() { // (B)
    console.log('B');
}).then(function() { // (C)
    console.log('C');
});

마이크로테스크 큐에 들어가는 API이냐, 테스크큐에 들어가는 API이냐에 따라 코드 실행의 흐름 및 타이밍이 달라지게되기 때문에 이를 인지하고 구분하여 사용할 수 있으면 좋다.

마이크로테스크 큐를 이용하는 API

  • MutationObserver - DOM의 변화를 감지할 수 있도록 하는 클래스
  • Node.js의 nextTick - 0.9버전부터 마이크로테스크 큐를 이용하도록 되어있다.

Reference