이벤트 루프, 마이크로태스크 큐와 매크로 태스크 큐에 대해서 말씀해 주세요.

면접용

JavaScript의 이벤트 루프(Event Loop)는 비동기 코드의 실행을 관리하는 핵심 메커니즘입니다. JavaScript는 싱글 스레드 기반의 언어이지만, 비동기 작업을 효율적으로 처리하기 위해 이벤트 루프를 사용합니다. 이벤트 루프는 Call Stack(콜 스택)과 Task Queue(태스크 큐)를 관리하며, 비동기 작업이 언제 실행될지를 결정합니다.

이벤트 루프의 주요 동작 방식은 다음과 같습니다. 먼저, JavaScript 코드가 실행되면 함수 호출이 Call Stack에 쌓입니다. Call Stack은 코드가 실행되는 공간으로, 모든 동기적 작업이 여기에서 처리됩니다. 하지만, 비동기 함수(setTimeout, fetch, Promise 등)가 실행되면 해당 작업은 Call Stack에서 빠져나와 Web API 영역에서 처리됩니다. 이후, Web API가 작업을 완료하면 콜백을 적절한 큐에 넣고, 이벤트 루프가 Call Stack이 비어 있는지를 확인한 후 큐에서 대기 중인 작업을 실행합니다.

Task Queue(태스크 큐)는 크게 두 가지로 나뉩니다. 첫 번째는 마이크로태스크 큐(Microtask Queue)이며, 두 번째는 매크로태스크 큐(Macrotask Queue)입니다. 마이크로태스크 큐에는 Promise의 .then(), MutationObserver, queueMicrotask()와 같은 작업이 포함되며, 매크로태스크 큐에는 setTimeout, setInterval, setImmediate, requestAnimationFrame 등의 작업이 포함됩니다. 이벤트 루프는 항상 Call Stack이 비어 있는 경우에만 큐에서 대기 중인 작업을 실행하는데, 실행 순서에서 중요한 점은 마이크로태스크가 매크로태스크보다 먼저 실행된다는 것입니다. 즉, Call Stack이 비워지면 이벤트 루프는 먼저 마이크로태스크 큐의 모든 작업을 실행한 후 매크로태스크 큐에서 작업을 가져와 실행합니다.

이러한 동작 원리는 비동기 코드의 실행 순서를 결정하는 데 중요한 역할을 합니다. 예를 들어, setTimeout의 콜백 함수보다 Promise.then()의 콜백 함수가 먼저 실행되는 이유가 바로 마이크로태스크가 매크로태스크보다 우선순위가 높기 때문입니다.


개념 설명

(이미지 출처: 모던 자바스크립트 딥다이브)

콜 스택 call stack

소스코드(전역 코드나 함수 코드 등) 평가 과정에서 생성된 실행 컨텍스트가 추가되고 제거되는 스택 자료구조인 실행 컨텍스트 스택이 콜 스택입니다.

함수를 호출하면 함수 실행 컨텍스트가 순차적으로 콜 스택에 푸시되어 순차적으로 실행되며, 자바스크립트 엔진은 단 하나의 콜 스택을 사용하기 때문에 최상위 실행 컨텍스트(실행 중인 실행 컨텍스트)가 종료되어 콜 스택에서 제거되기 전까지는 다른 어떤 태스크도 실행되지 않습니다.

힙 heap

힙은 객체가 저장되는 메모리 공간입니다. 콜 스택의 요소인 실행 컨텍스트는 힙에 저장된 객체를 참조합니다.

메모리에 값을 저장하려면 먼저 값을 저장할 메모리 공간의 크기를 결정해야 합니다. 객체는 원시 값과는 달리 크기가 정해져 있지 않으므로 할당해야 할 메모리 공간의 크기를 런타임에 결정(동적 할당)해야 합니다. 따라서 객체가 저장되는 메모리 공간인 힙은 구조화되어 있지 않다는 특징이 있습니다.

이벤트 루프 Event Loop

이벤트 루프는 비동기 함수의 실행을 관리합니다.

  1. Web API에서 비동기 처리된 함수가 종류되면, 적절한 큐로 함수를 이동

  2. Call Stack이 비었는지 확인

  3. 비었으면 큐에서 Call Stack으로 이동

이벤트 루프(Event Loop)는 Call Stack이 비어 있을 때 동작하며, Task Queue(마이크로태스크 큐 & 매크로태스크 큐)에서 다음 작업을 가져와 실행할지 결정하는 역할을 합니다. 즉, 비동기 함수가 실행될 때 즉시 이벤트 루프가 개입하는 것이 아니라, 그 함수가 "완료된 후" 콜백을 실행할 타이밍을 결정하는 것이 이벤트 루프의 역할입니다.

예시 코드

function foo() { 
	console.log('foo');
}

function bar() { 
	console.log('bar');
}

setTimeout(foo, 0); // 0초(실제는 4ms) 후에 foo 함수가 호출된다. bar();

Last updated