Event Loop

Take!·2025년 8월 15일

JavaScript

목록 보기
10/12

자바스크립트와 이벤트루프

자바스크립트는 싱글 스레드 언어이다. 이 '싱글 스레드' 라는 말은 한 번에 하나의 작업만 수행할 수 있다는 뜻이다. 그런데 실제로는 동시에 여러가지의 작업을 수행하는 것처럼 보인다. 이는 브라우저 내부의 멀티 스레드인 Web APIs에서 비동기 + 논블로킹으로 처리하고 있어서 가능한 것이다.
비동기 + 논블로킹은 메인 스레드가 작업을 다른 곳에 요청하여 대신 실행하고, 그 작업이 완료되면 이벤트나 콜백 함수를 받아 결과를 실행하는 방식을 말한다.

비동기로 동작하는 핵심 요소는 자바스크립트라는 언어가 아니라 브라우저가 가지고 있다고 보면 된다. Node.js의 경우 libuv라는 내장 라이브러리가 이 작업을 수행한다.

이벤트 루프

  • 싱글 스레드인 자바스크트의 작업을 멀티 스레드처럼 동시에 처리하게 하던가, 또는 여러 작업 중 어떤 작업을 우선적으로 동작시킬 것인지 결정하는 세심한 컨트롤을 하기 위해 존재하는 것이 바로 이벤트 루프 이다. 이벤트 루프는 브라우저 내부의 Call Stack, Callback Queue, Web APIs 등의 요소들을 반복적으로 모니터링하면서 비동기적으로 실행되는 작업들을 관리하고, 이를 정해진 순서대로 처리하여 프로그램의 실행 흐름을 제어하는 관리자라고 생각하면 된다.

브라우저의 내부 구성도

  • 브라우저 내에서는 다양한 역할을 하는 여러가지 장치들이 있지만, 비동기 코드의 동작 원리에 관여하는 구성요소만 추출하면 다음과 같다.

  • Call Stack: 호출 스택이라고도 하며, 자바스크립트 엔진이 코드의 실행을 위해 사용하는 메모리 구조이다.
  • Heap: 동적으로 생성된 자바스크립트 객체가 저장되는 공간이다.
  • Web APIs: 브라우저에서 제공하는 API 모음들이다. 비동기적으로 실행되는 작업들을 전담하여 처리한다.
  • Callback Queue: 비동기적 작업이 완료되면 실행되는 함수들이 대기하는 공간이다. (Web APIs에서 처리된 콜백함수들이 대기하는 공간)
  • Event Loop: 비동기 함수들을 적절한 시점에 실행시키는 관리자 역할

Web APIs의 종류

  • DOM: HTML 문서의 구조와 내용을 표현하고 조작할 수 있는 객체
  • XMLHttpRequest: 서버와 비동기적으로 데이터를 교환할 수 있는 객체.
  • Timer API: 일정한 시간 간격으로 함수를 실행시키거나 지연시키는 메서드 제공.
  • Console API: 개발자 도구에서 콘솔 기능을 제공.
  • Canvas API: canvase 태그 요소를 통해 그래픽을 그리거나 애니메이션을 만들 수 있는 메서드들을 제공.
  • Geolocation API: 웹 브라우저에서 사용자의 현재 위치 정보를 얻을 수 있는 메서드들을 제공.

모든 Web API들이 비동기적으로 동작되는 것은 아니다. DOM API는 동기적으로 처리되고, XMLHttpRequest, Timer API는 비동기적으로 호출된다.

Callback Queue의 구성

  • Callback Queue라는 명칭은 여러 종류의 Queue를 묶어 총칭하는 명칭이다. (macro)task queuemicro task queue 두 가지 종류가 있다.

  • Task Queue: 정식 명칭은 Macro Task Queue이나 보통 Task Queue로 불린다. setTimeout, setInterval, fetch, addEventListener와 같이 비동기로 처리되는 함수들의 Callback 함수가 들어가는 큐
  • Micro Task Queue: promise.then, process.nextTick, MutationObserver 와 같이 우선적으로 비동기로 처리되는 함수들의 Callback 함수가 들어가는 큐

    같은 queue 안에 적재되는 Callback 함수더라도, 그 안에서 비동기 작업의 우선순위가 또 결정된다. 예를들어 Promise와 Mutation Observer 콜백 중 Mustation Observer가 먼저 처리되는 경우가 있다.

Node.js의 내부 구성도

  • Node.js 환경에서도 브라우저와 거의 비슷한 구조를 가지고 있으나, 차이점이 있다면 내장된 libuv 라이브러리를 사용하여 비동기 IO를 지원한다는 점이다. 또한 브라우저에서는 Web API를 사용하여 DOM 조작, AJAX 호출, 타이머 및 애니메이션 등과 같은 다양한 작업을 처리하지만, Node.js에서는 Node.js만의 API를 사용하여 파일 시스템 액세스, 네트워크 액세스, 암호화, 압축 및 해제 같은 다양한 작업들을 처리한다.
  • V8(JS 엔진): Node.js에서 사용하는 JavaScript 엔진으로 코드를 컴파일하고 실행한다.
  • Bindings(Node API): Node.js 시스템과 V8엔진 간의 상호작용을 가능하게 하는 C++ 라이브러리이다.
  • libuv: Node.js에서 비동기 I/O 작업을 처리하기 위한 C 라이브러리이다.
  • Event Queue: 비동기 I/O 작업 결과를 저장하고 처리하기 위한 자료구조(웹 브라우저의 Tast Queue와 유사)
  • Event Loop: Event Queue에 저장된 I/O 작업 결과를 처리하고, 다음 작업을 수행하도록 하는 관리자이다.
  • Worker Threads: CPU 집약적인 작업을 처리하기 위해 Node.js 10버전부터 추가된 멀티 스레드. worker threads는 메인 스레드와 독립적인 V8 엔진 인스턴스를 가진다.

JavaScript 이벤트 루프 동작 과정

  • 브라우저의 Web APIs는 위 그림과 같이 각각 전용 작업을 처리하는 API 스레들로 구성된 집합을 일컫는다. 즉, setTimeout이 호출되면 Timer API라는 별도의 스레드에서 타이머 동작이 실행되는 것이며, fetch가 호출되면 Ajax API 스레드에서 네트워크 통신이 이루어지는 것이다.

  • 이벤트 루프는 비동기 함수 작업을 Web API에 옮기는 역할을 하고, 작업이 완료되면 Callback 함수들을 Queue에 적재했다가 다시 자바스크립트 CallStack에 적재시키는 역할을 한다. 따라서 해당 작업을 수행하는 주체는 JS 엔진이다. 따라서 이벤트 루프는 CallStack에 현재 실행중인 작업이 있는지 그리고 Task Queue에 대기 중인 작업이 있는지 반복적으로 확인하는 일종의 무한 루프만을 돌고 있다.

웹 브라우저와 Node.js의 Web API 차이

  • 구성들은 서로 비슷하지만 동작 측면에서 약간의 차이가 있다. 웹 브라우저의 Web APIs는 비동기 작업이 끝나면 스스로 callback queue에 적재하지만, Node.js API들은 이벤트 루프가 직접 옮겨준다.
profile
확장성 있는 설계와 유지보수가 용이한 클린 코드 지향하는 개발자입니다.

0개의 댓글