자바스크립트 엔진은 자바스크립트 코드를 실행하는 프로그램 또는 인터프리터이다.
자바스크립트 엔진의 대표적인 예는 Google V8 엔진으로, V8은 Chrome과 Node.js에서 사용한다.
자바스크립트 엔진은 Memory Heap과 Call Stack으로 구성되어 있다.
메모리 할당이 일어나는 곳이다. 프로그램에서 선언한 변수, 함수, 객체 등 모든 메모리 할당이 여기서 발생한다.
코드가 실행될 때 함수의 호출을 stack 형식으로 저장하는 자료구조이다.
콜 스택은 스크립트에서 현재 어떤 함수가 동작하고 있는지, 다음에는 어떤 함수가 호출되어야 하는지 등을 제어하고 기록한다.
자바스크립트는 콜 스택이 하나이기 때문에 단일 스레드(혹은 싱글 스레드) 기반의 언어라고 불린다.
따라서 동기적으로 한 번에 한 가지의 작업만 처리할 수 있다.
(자바스크립트는 단일 스레드 언어이지만, Web API를 통해 비동기 작업을 처리할 수 있음)
Stack: 후입선출(LIFO) 형태의 선형 자료구조로, 가장 최근에 들어온 데이터가 가장 먼저 나가는 방식
다음 그림과 같이 왼쪽에는 자바스크립트 엔진이 있고,
엔진 밖에는 Event Loop와 Callback Queue(또는 Task Queue), 그리고 Web APIs가 있다.
자바스크립트는 웹 브라우저뿐만 아니라 다양한 환경에서 실행될 수 있으며,
이때 코드가 실행되는 환경을 런타임(runtime)이라고 한다.
즉, Event Loop와 Callback Queue, Web APIs는 런타임 구성 요소에 해당한다.
Node.js, Chrome 등의 브라우저들은 자바스크립트가 구동되는 환경이므로 자바스크립트 런타임이라고 한다.
브라우저에서 자체 제공하는 API로, 비동기 작업 등을 실행할 수 있는 DOM, Ajax, setTimeout 등이 있다.
위에서 웹 브라우저 환경(그림)을 보면 Web APIs는 JS 엔진 밖에 존재하는 것을 알 수 있다.
자바스크립트 엔진까지가 자바스크립트를 동기적으로 작동시킨다면,
Web APIs부터는 자바스크립트를 비동기적으로 작동시킬 수 있도록 지원하는 역할을 한다.
Call Stack에서 실행된 비동기 함수는 Web API를 호출하고, Web API는 콜백 함수를 Callback Queue에 push 한다.
자바스크립트에서 비동기로 호출되는 함수들은 Call Stack에 쌓이지 않고 Callback Queue로 보내지며,
선입선출(FIFO) 방식에 따라 출력된다.
예를 들어, setTimeout에서 타이머가 완료되고 실행되는 함수(첫 번째 인자),
addEventListener에서 click 이벤트가 발생했을 때 실행되는 함수(두 번째 인자) 등이 저장된다.
Callback Queue에는 Task Queue, Microtask Queue, Animation Frames가 있다.
Web API에서 비동기 작업들이 실행된 후 호출되는 콜백함수들이 기다리는 공간이며, 이벤트 루프가 정해준 순서대로 위치하게 된다.
이벤트 루프는 Call Stack과 Callback Queue를 관찰하는 역할을 한다.
Call Stack이 비어있을 경우, Callback Queue에서 함수를 꺼내 Call Stack에 추가하는 기능을 한다.
이와 같은 반복적인 행동을 틱(tick)이라고 부른다.
이벤트 루프가 Callback Queue에서 Call Stack으로 콜백 함수를 넘겨주는 작업은 콜 스택에 쌓여있는 함수가 없을 때만 수행한다.
요약하자면, 일반적인 작업은 Call Stack에서 이뤄지며, 시간이 소요되는 작업들(setTimeout, 이벤트, http 요청 등)은
Web APIs에서 대기하다가 Callback Queue로 보내진다.
콜 스택이 비어있을 경우에만, 콜백 큐에 저장되어 있던 작업들을 Call Stack으로 보낸다.