이벤트 루프와 태스크 큐(마이크로, 매크로)

이경택·2024년 9월 8일

자바스크립트

목록 보기
1/1
post-thumbnail

이벤트 루프가 어떤 것이고 어떻게 동작하는 지 알기 전에 자바스크립트 엔진과 자바스크립트 런타임이 어떻게 구성되어있고 콜백큐(태스크큐)로 어떻게 이동되는지 알아야 할 것 같다.

자바스크립트

V8 자바스크립트 엔진은 크게 두 부분으로 구성된다.

  • 메모리 힙: 메모리 할당이 이루어지는 곳
  • 콜 스택(호출스택): 코드가 실행되면서 스택이 쌓이는 곳

자바스크립트는 콜 스택이 하나이기에 싱글 스레드 언어이다.

런타임 환경에는 WebAPI와 이벤트루프, 콜백큐가 있다.

  • WebAPI: 브라우저에서 제공되는 API. setTimeout, HTTP 요청 메서드, DOM 이벤트
  • 콜백큐
    - 이벤트가 발생한 후 호출되어야 하는 콜백 함수들이 대기하는 공간.
    - 이벤트 루프가 정해준 순서대로 대기하고 있다.
  • 이벤트루프: 이벤트 발생 시 호출할 콜백 함수들을 관리하며, 호출된 콜백함수의 실행 순서 관리.

비동기 동작 원리

  1. 자바스크립트 엔진의 콜 스택에 실행될 함수가 쌓이고 실행된다.
  2. 비동기 함수는 WebAPI에 의해 콜백 큐(태스크 큐)로 추가된다.
  3. 이벤트 루프는 콜백 큐와 콜 스택을 번갈아가며 확인하며 콜 스택이 비면 콜백 큐의 함수를 추가한다.

이벤트 루프

이벤트 루프란 싱글 스레드로 동작하는 JavaScript를 브라우저에서 동시성을 제공하기 위한 동작 방식을 의미

→ 즉, 자바스크립트는 싱글 스레드가 맞지만 자바스크립트 런타임은 싱글스레드가 아니다.

이벤트 루프

이벤트 루프의 동작 순서

  1. 호출스택이 비었는지 지속적으로 확인
  2. 호출스택이 비게 되면 제일 먼저 마이크로 태스크 큐를 확인하고 가장 오래된 태스크부터 꺼내서 호출스택으로 전달해 주는데, 이걸 마이크로태스크 큐가 비어질 때까지 수행.
  3. 모든 마이크로태스크가 처리된 직후, 렌더링 작업이 필요하면 렌더링을 수행
  4. 매크로 태스크 큐를 확인
  5. 매크로 태스크 큐에서 가장 오래된 태스크 하나를 꺼내 호출 스택에 전달
  6. 다시 1번으로 돌아감

태스크 큐

태스크 큐의 종류는 마이크로 태스크 큐와 매크로 태스크 큐, Animation frames가 있다.

자바스크립트에서 비동기 함수들은 콜 스택에 쌓이지 않고 WebAPI에서 처리한 후 태스크 큐로 보내진다.

실행 순서

마이크로 태스크 큐 → Animation frames → 매크로 태스크 큐

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

  • 구성
    • Promise 핸들러 + await , process.nextTick, Object.observe, MutationObserver
  • 특징
    • FIFO(First-In-First-Out)로 먼저 들어온 작업을 먼저 실행한다.
    • 1번 수행할 때 큐를 모두 비운다.
      → 즉, 마이크로 태스크 큐는 새로운 마이크로 태스크를 큐에 넣을 수 있으며, 이러한 새로운 마이크로 태스크는 다음 작업이 실행되기 전과 현재 이벤트 루프 반복이 끝나기 전에 실행된다. (새로운 태스크도 바로 실행)

매크로 태스크 큐

  • 구성
    • I/O, UI rendering, setTimeout, setInterval, setImmediate
  • 특징
    • 1번 수행할 때 하나의 task만 비운다.

작업 순서 중 필수로 알아야 할 부분

브라우저는 매크로 태스크 하나를 처리할 때마다 마이크로 태스크 전부를 다 처리하고 렌더링을 수행함

마이크로 태스크가 모두 처리되기 전까지는 UI 렌더링이나 네트워크 요청은 절대 일어나지 않음

위의 절차들을 아래 예시를 통해 더 자세히 생각해보자

태스크 큐와 이벤트 루프

  1. 현재 호출스택에 작업들이 많아서 자바스크립트 엔진이 바쁜 와중에 여러 비동기 작업들이 큐에 쌓여있는 상황이다.
  2. 이벤트 루프는 태스크들을 처리하기 위해 호출 스택이 비었는지 계속 확인하며 호출 스택이 비었다면, 이벤트 루프는 가장 먼저 마이크로 태스크 큐에 쌓여있는 태스크들을  Promise then -> Promise then -> Observer callback 순서로 모두 처리할 것이다.
    그리고 매크로 태스크 큐를 처리하기 전에 UI 렌더링 작업이 필요하면 렌더링을 이때 수행한다.
  3. 이제 매크로태스크 큐의 click callback을 처리하고 다시 마이크로 태스크 큐를 확인한다.
    만약 마이크로 태스크 큐에 처리할 태스크들이 또 쌓여있다면 그것들을 모두 처리한 후 다시 렌더링 작업을 수행하고 매크로 태스크의 setTimeout callback을 처리한다.

동기, 비동기

동기

작업이 순차적으로 진행된다. → 작업이 끝날 때 까지 내가 기다린다.

요청한 작업을 내가 기다릴 것인가?

비동기

작업이 순차적으로 진행되지 않는다. → 작업이 끝날 때 까지 내가 기다리지 않는다.

요청한 작업이 끝날 때 까지 내가 기다리고 다음 작업을 시작할 것인가?

동기/비동기 ≠ 블로킹/논블로킹

  • 블로킹 / 논블로킹
    블로킹 = 요청에 대한 결과값을 받을 때 까지 기다린다.
    논블로킹 = 요청에 대한 결과값을 받을 때 까지 기다리지 않는다.
  • 병렬성 / 동시성
    병렬성 = 동시에 여러 작업을 처리하는 것
    동시성 = 동시에 여러 작업을 처리하는 것처럼 보이는 것
profile
한 줄로 소개 할 수 없는 개발자

0개의 댓글