JavaScript는 싱글 스레드 기반 언어로, 한 번에 하나의 작업만 실행할 수 있다.
코드를 한 줄씩 실행하면서 현재 실행 중인 코드(함수)를 콜 스택(또는 호출 스택)이라는 공간에 쌓아두고 하나씩 처리하게 되는데, API 요청 같은 비동기 작업을 실행한다면 다른 작업을 동시에 처리할 수 없어 긴 시간동안 실행이 멈추게 될 것이다.
이런 문제를 피하기 위해 JavaScript에는 이벤트 루프(Event Loop)와 태스크 큐(Task Queue)가 존재한다.
JavaScript는 싱글 스레드의 문제를 극복하기 위해 콜 스택 외에 백그라운드에서 작업을 처리할 공간이 필요한데, 브라우저의 Web APIs를 활용해서 비동기 작업을 처리한다.(Node.js는 libuv라는 C++ 기반의 비동기 I/O 라이브러리를 활용함)
비동기 API(fetch().then(), XMLHttpRequest())의 응답 처리, 비동기 함수(setTimeout, addEventListener)의 콜백이 태스크 큐에 쌓이고 콜 스택이 비어있을 때 이벤트 루프에 의해 하나씩 실행된다.
콜 스택과 태스크 큐를 관리하여 비동기 코드의 실행 순서를 제어하는 장치
쉽게 말해, 처리할 태스크가 있을 때, 콜 스택이 비어있는지 계속 확인하다가 콜 스택이 비는 순간 태스크 큐의 완료된 작업들을 처리하는 것이다.
태스크 큐는 태스크의 종류에 따라 매크로 태스크 / 마이크로 태스크 두 가지로 나뉜다.
태스크 큐에서 매크로 태스크들을 모아두는 공간이다.
태스크 큐에서 마이크로 태스크들을 모아두는 공간이다.
setTimeout(() => console.log("timeout"));
Promise.resolve()
.then(() => console.log("promise"));
console.log("code");
위의 코드는
1. 동기 코드인 console.log("code")가 가장 먼저 처리되고,
2. 그 다음으로 마이크로 태스크인 Promise.then(),
3. 그 다음으로 매크로 테스크인 setTimeout이 처리된다.
code
promise
timeout