JavaScript 런타임, 이벤트 루프, 태스크큐 vs 마이크로태스크 큐

seo·2021년 10월 19일
2

📒JavaScript

목록 보기
1/2
post-thumbnail

자바스크립트 엔진

대표적인 자바스크립트 엔진은 구글 크롬의 V8이다.

V8 엔진은 크게 두 부분으로 구성된다.

  • Memory Heap: 메모리 할당이 이루어지는 곳, 동적으로 생성되는 객체들을 할당한다. 구조화되지 않은 넓은 메모리 영역을 지칭한다.
  • Call Stack: 코드가 실행되면서 스택 프레임이 쌓이는 곳, 종료될 때마다 해당 스택 프레임이 pop된다.

싱글 스레드

자바스크립트 엔진은 하나의 Memory Heap과 Call Stack을 가지고 있다. 따라서 구조적으로 한번에 하나의 코드만 동기적으로 실행이 가능한 싱글스레드 언어이다. 자바 스크립트가 처음 나왔을때는 멀티프로세서 컴퓨터가 거의 없었고 당시 자바스크립트로 처리할 코드의 양은 상대적으로 적었기 때문이다.
시간이 지나면서 컴퓨터가 멀티 코어 시스템으로 바뀌었고, 싱글 스레드의 한계에서 벗어날 수 있는 방법을 찾아야했다.

자바스크립트 런타임

런타임은 해당 프로그래밍 언어로 작성된 코드가 구동되는 환경이다. 자바스크립트 코드는 다음의 두 가지 런타임 환경 중 하나에서 실행될 수 있다.

  • Chrome, Firefox등의 웹 브라우저
  • Node

Web API

Web API는 웹 브라우저에 구현된, 자바스크립트가 실행되는 런타임 환경에 존재하는 별도의 API이다. setTimeout setInterval setImmediate AJAX DOM 등이 있다.

Event Loop

자바스크립트가 구동되는 환경(브라우저,Node)은 여러 스레드가 사용된다. 여러 스레드가 사용되는 구동 환경이 자바스크립트 엔진과 연동하기 위해 사용되는 장치가 '이벤트 루프' 이다.

  • 스레드 안에 있는 코드들을 스케줄링하고 실행시키는 역할을 담당한다.
  • 브라우저에 존재하는 여러 Queue들에 우선순위를 부여해 어떤 Task를 먼저 수행할지 결정한다.
  • 이벤트 루프의 역할은 콜 스택과 태스크 큐를 주시하는 것이다.
  • 이벤트 루프는 하나 이상의 Task Queue를 갖는다.

Task Queue(Macro Queue)와 MicroTask Queue

📌Callback queue, Task queue, Macro queue 용어
어떤 블로그에서는 Task Queue의 종류에 Macro queue와 Micro queue가 들어가는거라고 되어있고 공식 문서에는 The microtask queue is not a task queue. 라고 되어있었다. 찾아보니 Microtask queue와 Task queue(Macrotask queue)가 다른것이고 Macrotask와 Task queue는 같은 것이었다.
많은 곳에서 Callback queue와 Task queue를 같은 의미로 사용하고 있었는데 공식 문서에 Task queue로 나와있어서 Task queue로 적었다.

API에 따라 Task Queue를 사용하거나 Microtask Queue를 사용한다.

기본적으로 비동기 방식으로 작업을 수행 해야하는 경우 MicroTask를 사용한다. (그렇지 않으면 Task사용을 권한다.)

Task Queue

Task queues are sets, not queues, because step one of the event loop processing model grabs the first runnable task from the chosen queue, instead of dequeuing the first task.

Task Queue는 Task의 집합이다. 단순히 큐의 첫 번째 Task를 가져오는 것이 아니라, 실행가능한 가장 오래된 Task를 가져온다.

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

Microtask Queue

비동기 작업을 처리하려면 적절한 관리가 필요하다. 이를 위해 ECMA에선 PromiseJobs라는 내부 큐를 명시한다. V8 엔진에서는 이를 Microtask queue라고 부른다. Microtask Queue는 Task Queue와 같은 계층에 존재한다.

  • 먼저 들어온 작업을 먼저 실행한다.(FIFO)
  • 작업이 종료되고 실행 컨텍스트가 비어있을 때마다 마이크로태스크 큐에 있는 작업이 차례로 실행된다.
  • 표준 API인 queueMicrotask(func)를 사용하면 함수 func를 마이크로태스크 큐에 넣어 처리할 수 있다.

Microtask Queue - process.nextTick , Promises , queueMicrotask , MutationObserver

이벤트 루프의 동작방식

  1. task queue에서 가장 오래된 task를 꺼내 실행한다.
  2. 모든 microtask를 실행한다. 👉 큐가 빌때까지 이어지며 task는 오래된 순서대로 처리
  3. 랜더링 할것이 있으면 처리한다.
  4. task queue가 비어있으면 새로운 task가 나타날 때까지 대기한다.
  5. 1번으로 돌아간다.

예시

console.log('script start'); //A

setTimeout(function () {
  console.log('setTimeout'); //B
}, 0);

Promise.resolve()
  .then(function () {//C
    console.log('promise1');
  })
  .then(function () {//d
    console.log('promise2');
  });

console.log('script end'); //E
  1. Call stack에는 전역 실행 객체가 있고, 'Run script'라는 task가 task queue에 들어있다.
  2. 이벤트 루프는 task queue에 있는 'Run script' task를 실행한다.
  3. A console.log('script start')가 Call Stack에 쌓였다가 'script start'를 출력하고 pop된다.
  4. B setTimeout(cb,0)함수를 Call Stack에서 Web API로 이동시키고 타이머를 실행시킨다. 타이머가 종료되면 callback함수 cb가 Task queue에 들어간다.
  5. C callback함수가 microtask queue에 들어간다.
  6. E console.log('script end')가 Call Stack에 쌓였다가 'script end'를 출력하고 pop된다.
  7. Call stack이 비었기때문에, 이벤트 루프는 microtask queue에 있는 Promise callback 함수를 실행시킨다.
  8. 'promise1'이 출력
  9. D 콜백함수를 microtask queue에 등록한다.
  10. 이벤트 루프는 다음 microtask queue인 D callback함수를 실행시킨다.
  11. 'promise 2'출력
  12. 렌더링 할 것이 있으면 렌더링을 한다.
  13. task queue에 있는 setTimeout의 callback함수를 실행시킨다.
  14. 'setTimeout'이 출력

참고

0개의 댓글