싱글 스레드 언어자바스크립트 런타임자바스크립트 엔진Wab APIsCallback Queue (=Macro Task Queue) Event LoopMicro Task Queue 자바스크립트 런타임 과정
싱글 스레드 언어
자바스크립트는 싱글 스레드 언어이다. 그렇기 때문에 한 번에 하나의 작업을 동기적으로 실행한다.
예를 들어서 이런 코드가 있다고 해보자.
이 코드는
console.log()
를 총 3번 실행시키는데, console.log('2')
는 while
문을 통해서 반복문이 종료된 뒤에 실행한다.이 코드를 브라우저 콘솔에서 실행하면 이런 식으로 동작한다.
실행 결과를 보면, 먼저 1이 실행되고
while
문이 종료한 뒤 2가 실행되고 바로 3이 실행되는 것을 확인할 수 있고, 이때 페이지가 스크롤이나 클릭 등의 이벤트가 일시적으로 동작하지 않는 것도 확인할 수 있다. 이것은 자바스크립트가 싱글 스레드의 동기적 처리 방식으로 실행되기 때문이다.
그 다음으로는
setTimeout
을 통해서 코드를 지연시키려는 코드가 있다고 해보자.이 코드는
setTimeout
을 통해 2를 1초 뒤에 실행하고(*) while
문을 통해서 반복문이 종료되면 3을 실행(**)하기 위해 작성되었다. 코드만 봤을 때는 1이 먼저 실행되고 1초 뒤에 2가 실행되고 2초 이상 걸리는 while
문의 반복문이 종료되면 3이 실행되는 동기적인 결과가 나올 것 같지만, 예상과는 다르게 1이 실행되고 2초 이상 뒤에 3이 실행되고 2가 실행되는 비동기적인 순서로 실행되는 것을 확인할 수 있다.자바스크립트는 싱글 스레드 언어이기 때문에 하나의 작업만 실행되어야 되는데 어떻게 이런 결과가 나올 수 있을까?
이 과정을 설명하기 전에 먼저 관련된 용어를 정리해보려고 한다.
자바스크립트 런타임
런타임이란 프로그램을 실행할 수 있는 환경을 의미하는데 자바스크립트 런타임은 웹 브라우저와 Node.js 등이 있다.
자바스크립트 런타임은 자바스크립트 엔진과 Web APIs, 콜백 큐(Callback Queue), 이벤트 루프(Event Loop) 등으로 구성되어 있다.
자바스크립트 엔진
자바스크립트 엔진은 메모리 힙(memory heap) 과 콜 스택(call stack)으로 구성되어있다.
메모리 힙은 메모리 할당이 발생하는 곳이고 콜 스택은 코드가 실행될 때 스택 자료구조를 통해 실행 컨텍스트가 쌓이는 곳이다.
Wab APIs
Web API 는 브라우저에서 setTimeout, DOM API, fetch(AJAX) 등의 API 제공한다.
Callback Queue (=Macro Task Queue)
콜백 큐는 Script 태그나 Web API 의 항목들이 대기하는 Queue 자료구조 형식의 배열이다.
Event Loop
이벤트 루프는 콜 스택을 관찰하면서 콜 스택이 모두 비워진 경우에 콜백 큐에서 콜백 함수를 스택에 추가하여 실행한다. 이때 콜백 큐와 마이크로 태스크 큐 중에 마이크로 태스크 큐에 있는 항목을 우선적으로 콜 스택에 추가한다.
Micro Task Queue
Promise(), queueMicrotask() 가 추가되고 콜백 큐보다 우선순위가 높아 먼저 이벤트 루프를 통해 콜 스택으로 이동한다.
자바스크립트 런타임 과정
위의 예제를 과정을 통해 확인해보자.
위에서 실행했던 예제를 다시 가져왔고
Promise()
를 사용한 코드를 추가하였다. (*)해당 코드는 자바스크립트 런타임 환경에서 이런 과정을 거친다.
- 콜 스택에
console.log('1')
이 추가된 뒤 실행되고 제거된다.
- 콜 스택에
setTimeout(cb)
이 추가된다.
- 콜 스택에서
setTimeout(cb)
이 실행되어cb()
이 Web APIs 으로 이동하고setTimeout(cb)
이 콜 스택에서 제거된다. (이때 Web APIs 에서setTimeout(cb)
의 타이머가 동작한다.)
- 콜 스택에
Promise.resolve()
와then(cb)
이 추가되고cb()
은 마이크로 태스크 큐로 이동한다.
- 콜 스택에
slow('3')
이 추가되고 실행되어console.log('3')
가 실행되고 제거된다.
- 4~5번이 실행되고 있는 동안
setTimeout(cb)
의 타이머가 완료되면 Web APIs 에 있던cb()
이 콜백 큐로 이동한다.
- 마이크로 태스크 큐에
Promise()
의cb()
이 있고 콜백 큐에setTimeout
의cb()
가 있는 상태에서 마이크로 태스크 큐의 우선순위가 더 높기 때문에 이벤트 루프를 통해서Promise()
의cb()
가 먼저 콜 스택에 추가되어 실행되고 제거된다.
- 콜 스택 작업과 마이크로 태스크 큐의 작업도 모두 완료되었기 때문에 이벤트 루프를 통해 콜백 큐에 있는
cb()
이 콜 스택으로 이동된다.
- 콜 스택에
cb()
가 추가되고 실행된 다음 콜 스택에서 제거된다.
정리를 하기 전에 자바스크립트 런타임 공부를 하면서 비슷한 의미이지만 설명하는 용어가 다 달라서 처음에는 당황했지만(콜백 큐, 매크로 태스트 큐, 태스크 큐) 정리를 하니까 어느 정도 머리의 복잡함이 해소된 것 같다.
참고