브라우저의 Event Loop
는 JavaScript의 비동기 처리를 담당하는 메커니즘입니다. 이를 통해 웹 페이지에서 발생하는 다양한 이벤트와 작업을 조율하여 순차적으로 실행되도록 관리됩니다.
자바스크립트는 싱글 스레드(single-threaded) 언어로, 한 번에 하나의 작업만 처리할 수 있습니다. 그럼에도 불구하고 JavaScript는 비동기 작업을 처리할 수 있는데, 이는 Event Loop를 통해 가능합니다.
브라우저 위에서 웹 애플리케이션이 실행되는 순간, 자바스크립트 엔진이 우리가 작성한 소스 코드를 한줄 한줄 해석하고 실행해나갑니다.
자바스크립트 엔진에는 할당된 데이터들을 저장하는 Heap 메모리 영역과, 실행하는 순서에 따라서 함수들이 쌓이는 Call Stack 공간을 가지고 있습니다. 함수가 호출되면 해당 함수의 실행 컨텍스트가 스택에 쌓이고, 함수가 반환될 때 스택에서 제거됩니다.
자바스크립트 엔진은 소스 코드를 해석해 나가면서 해당 영역들을 사용합니다.
Web APIs는 브라우저 환경에서 제공하는 API들로, 비동기 작업을 처리할 수 있도록 도와줍니다. setTimeout, fetch, event listener, XMLHttpRequest 등이 이에 해당합니다. 이러한 API들은 비동기 작업을 요청하고, 해당 작업이 완료되면 Callback 함수를 호출하거나 Promise를 해결합니다.
setTimeout을 예로 들어보겠습니다. 현재 Call Stack 안에 setTimeout 함수가 들어있다고 가정하겠습니다.
자바스크립트 엔진이 Call Stack에 들어있는 setTimeout을 실행하면, 브라우저는 지정한 시간이 지나고 콜백 함수를 Callback Queue에 넣습니다.
Callback Queue
는 비동기 작업이 완료되면 해당 작업의 콜백 함수나 Promise의 then 메서드와 같은 핸들러가 추가되는 공간입니다.
Callback Queue를 좀 더 세분화 하자면 setTimeout의 콜백 함수는
Task Queue
에 담기고 Promise의 then 메서드는Microtask Queue
에 담깁니다.
여기서 콜백 함수는 언제 실행이 될까요?
브라우저에는 Call Stack과 Callback Queue를 계속 관찰하는 Event Loop
가 있습니다. Event Loop는 for 루프와 while 루프처럼 계속해서 순회를 돌면서 Call Stack과 Callback Queue를 관찰합니다.
만약 Call Stack에 작업이 남아있다면 작업이 끝날때 까지 기다립니다. 완전히 비워져 자바스크립트 엔진이 더 이상 일을 하고 있지 않을 때, Callback Queue에 있는 콜백 함수를 하나씩 Call Stack에 넣습니다. 그리고 자바스크립트 엔진이 함수를 실행시킵니다.
여기서 Task Queue
와 Microtask Queue
차이점을 살펴보겠습니다. Event Loop는 루프를 돌다가 Microtask Queue에 작업이 생기면, 함수들을 Call Stack에 옮겨 모두 실행시키고 Microtask Queue의 공간이 비어있을 때까지 그 곳에 머물러 있습니다.
반면에 Task Queue에 콜백 함수가 여러개 있으면, Call Stack이 비어있을 때까지 기다렸다가 한번에 하나씩 Call Stack에 옮겨 실행시키고 순회를 계속합니다. 돌면서 다시 Task Queue의 콜백 함수를 또 하나씩 Call Stack에 옮겨 실행시킵니다.
이런 차이점으로 인해 Microtask Queue의 작업이 여러개라면, 그 작업들이 끝날때까지는 화면의 재렌더링이 발생하지 않지만 Task Queue의 작업이 여러개라면, 하나씩 실행시키면서 순회를 계속하기 때문에 화면의 재렌더링이 발생합니다.