본문 바로가기
자바스크립트

매크로 태스크 큐(Macro Task Queue), 애니메이션 프레임 큐(Animation Frame Queue), 마이크로 태스크 큐(Micro Task Queue)

by ihateindex 2024. 10. 29.

큐의 우선순위

 

자바스크립트 런타임의 큐에는 매크로 태스크 큐(태스크 큐), 애니메이션 프레임 큐, 마이크로 태스크 큐가 있습니다. 이 큐간의 우선순위는 위 사진과 같이 마이크로 태스크 큐가 가장 우선순위가 높고 애니메이션 프레임 큐, 매크로 태스크 큐의 순서대로 순위가 매겨져 있습니다.

 

매크로 태스크 큐 (Macro Task Queue)

매크로 태스크 큐 또는 태스크 큐라고 불리우는 큐입니다. 자바스크립트의 콜 스택이 모두 비워져 이벤트 루프가 작동 시 매크로 태스크 큐에 태스크가 있다면 해당 태스크를 콜 스택으로 옮겨 실행합니다. 매크로 태스크 큐의 특징은 이벤트 루프 1번 수행시 1개의 태스크만 실행된다는 것입니다.

 

매크로 태스크 큐에는 setTimeout, setInterval, DOM, I/O, Network request, Event Handlers이 있습니다.

애니메이션 프레임 큐 (Animation Frame Queue)

애니메이션 프레임 큐는 브라우저의 렌더링을 담당하고 있는 큐입니다. 콜 스택이 모두 비워지면 이벤트 루프가 작동되어 애니메이션 프레임 큐의 태스크가 콜 스택으로 옮겨져 실행됩니다. 애니메이션 프레임 큐는 매크로 태스크 큐와 다르게 이벤트 루프 1번 수행시 모든 태스크를 순차적으로 실행해 큐를 모두 비운다는 특징이 있습니다.

 

애니메이션 프레임 큐에는 a태그를 클릭하면 브라우저의 커서가 화살표에서 손가락 모양으로 바뀌는 것과 같은 애니메이션 렌더링 관련 태스크들이 속해 있습니다.

마이크로 태스크 큐(Micro Task Queue)

마이크로 태스크 큐는 가장 우선순위가 높은 큐입니다. 콜 스택이 모두 비워져 이벤트 루프가 작동하면 가장 먼저 실행되는 큐이고, 애니메이션 프레임 큐와 동일하게 이벤트 루프 1번 실행시 모든 태스크를 순차적으로 실행해 큐를 모두 비웁니다.

 

마이크로 태스크 큐에는 Promise Callback, mutation observer API, await in async func이 있습니다.

 

 

태스크 큐의 우선순위와 실제 실행 시간

아래 예시 코드는 태스크 큐들의 우선순위를 확인하기 위한 콘솔로그를 찍는 코드입니다.

console.log('1'); // 동기 코드

setTimeout(() => {
    console.log('2'); // 매크로태스크
}, 0);

Promise.resolve().then(() => {
    console.log('3'); // 마이크로태스크
});

requestAnimationFrame(() => {
    console.log('4'); // 애니메이션 프레임
});

console.log('5'); // 동기 코드

 

해당 코드를 브라우저(자바스크립트 런타임)의 콘솔 창에서 실행하면 우선순위에 따라 어떤 결과가 나올까요?

 

 

 

 

우선순위에서 설명한 것과 다르게 매크로 태스크 큐(2번)가 애니메이션 프레임 큐(4번)보다 먼저 찍힌 것이 보인다.

 

본문에서 설명한 우선순위와 달리 매크로 태스크 큐(2번)가 애니메이션 프레임 큐(4번)보다 먼저 출력되는 것을 볼 수 있습니다.

 

왜일까요..?

이는 우선순위와 실제 실행 시간이 서로 다르기 때문입니다. 

 

실제 실행 시간을 살펴보면,

- requestAnimationFrame은 브라우저의 다음 리페인트 직전에 실행되며, 브라우저는 보통 60fps(약 16.7ms마다) 화면을 업데이트합니다.

- setTimeout(0)는 약 4ms가 지연된 뒤 실행됩니다.

 

이러한 차이로 인해, 애니메이션 프레임 큐가 우선순위가 더 높아 먼저 처리되지만 실제 콜백은 다음 화면 갱신(약 16.7ms)까지 대기해야 합니다. 반면 setTimeout(0)은 단 4ms만 기다리면 되므로, 결과적으로 콘솔에는 2번이 4번보다 먼저 출력되는 것입니다.

 

 

아래와 같이 setTimeout의 지연시간을 늘려주면 우선순위와 동일한 순서로 콘솔이 찍히는 것을 볼 수 있습니다.

console.log('1'); // 동기 코드

setTimeout(() => {
    console.log('2'); // 매크로태스크
}, 100);

Promise.resolve().then(() => {
    console.log('3'); // 마이크로태스크
});

requestAnimationFrame(() => {
    console.log('4'); // 애니메이션 프레임
});

console.log('5'); // 동기 코드

 

 

본문에서 설명한 것 과 같이 동기 코드들(1번, 5번)이 모두 실행되어 콜 스택이 비워지게 되면 우선순위에 따라 마이크로 태스크 큐(3번), 애니메이션 프레임 큐(4번), 매크로 태스크 큐(2번)의 순서대로 실행되는 것을 확인 할 수 있습니다.