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

V8 자바스크립트 엔진은 크게 두 부분으로 구성된다.
- 메모리 힙: 메모리 할당이 이루어지는 곳
- 콜 스택(호출스택): 코드가 실행되면서 스택이 쌓이는 곳
자바스크립트는 콜 스택이 하나이기에 싱글 스레드 언어이다.
런타임 환경에는 WebAPI와 이벤트루프, 콜백큐가 있다.
- WebAPI: 브라우저에서 제공되는 API.
setTimeout, HTTP 요청 메서드, DOM 이벤트 등
- 콜백큐
- 이벤트가 발생한 후 호출되어야 하는 콜백 함수들이 대기하는 공간.
- 이벤트 루프가 정해준 순서대로 대기하고 있다.
- 이벤트루프: 이벤트 발생 시 호출할 콜백 함수들을 관리하며, 호출된 콜백함수의 실행 순서 관리.
비동기 동작 원리
- 자바스크립트 엔진의 콜 스택에 실행될 함수가 쌓이고 실행된다.
- 비동기 함수는 WebAPI에 의해 콜백 큐(태스크 큐)로 추가된다.
- 이벤트 루프는 콜백 큐와 콜 스택을 번갈아가며 확인하며 콜 스택이 비면 콜백 큐의 함수를 추가한다.
이벤트 루프
이벤트 루프란 싱글 스레드로 동작하는 JavaScript를 브라우저에서 동시성을 제공하기 위한 동작 방식을 의미
→ 즉, 자바스크립트는 싱글 스레드가 맞지만 자바스크립트 런타임은 싱글스레드가 아니다.

이벤트 루프의 동작 순서
- 호출스택이 비었는지 지속적으로 확인
- 호출스택이 비게 되면 제일 먼저 마이크로 태스크 큐를 확인하고 가장 오래된 태스크부터 꺼내서 호출스택으로 전달해 주는데, 이걸 마이크로태스크 큐가 비어질 때까지 수행.
- 모든 마이크로태스크가 처리된 직후, 렌더링 작업이 필요하면 렌더링을 수행
- 매크로 태스크 큐를 확인
- 매크로 태스크 큐에서 가장 오래된 태스크 하나를 꺼내 호출 스택에 전달
- 다시 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
- 특징
작업 순서 중 필수로 알아야 할 부분
브라우저는 매크로 태스크 하나를 처리할 때마다 마이크로 태스크 전부를 다 처리하고 렌더링을 수행함
→ 마이크로 태스크가 모두 처리되기 전까지는 UI 렌더링이나 네트워크 요청은 절대 일어나지 않음
위의 절차들을 아래 예시를 통해 더 자세히 생각해보자

- 현재 호출스택에 작업들이 많아서 자바스크립트 엔진이 바쁜 와중에 여러 비동기 작업들이 큐에 쌓여있는 상황이다.
- 이벤트 루프는 태스크들을 처리하기 위해 호출 스택이 비었는지 계속 확인하며 호출 스택이 비었다면, 이벤트 루프는 가장 먼저 마이크로 태스크 큐에 쌓여있는 태스크들을 Promise then -> Promise then -> Observer callback 순서로 모두 처리할 것이다.
그리고 매크로 태스크 큐를 처리하기 전에 UI 렌더링 작업이 필요하면 렌더링을 이때 수행한다.
- 이제 매크로태스크 큐의 click callback을 처리하고 다시 마이크로 태스크 큐를 확인한다.
만약 마이크로 태스크 큐에 처리할 태스크들이 또 쌓여있다면 그것들을 모두 처리한 후 다시 렌더링 작업을 수행하고 매크로 태스크의 setTimeout callback을 처리한다.
동기, 비동기
동기
작업이 순차적으로 진행된다. → 작업이 끝날 때 까지 내가 기다린다.
요청한 작업을 내가 기다릴 것인가?
비동기
작업이 순차적으로 진행되지 않는다. → 작업이 끝날 때 까지 내가 기다리지 않는다.
요청한 작업이 끝날 때 까지 내가 기다리고 다음 작업을 시작할 것인가?
동기/비동기 ≠ 블로킹/논블로킹
- 블로킹 / 논블로킹
블로킹 = 요청에 대한 결과값을 받을 때 까지 기다린다.
논블로킹 = 요청에 대한 결과값을 받을 때 까지 기다리지 않는다.
- 병렬성 / 동시성
병렬성 = 동시에 여러 작업을 처리하는 것
동시성 = 동시에 여러 작업을 처리하는 것처럼 보이는 것