자바스크립트의 동시성을 책임지는 이벤트 루프(Event Loop) 동작 원리

Kingmo·2022년 4월 30일

자바스크립트는 하나의 콜 스택만을 사용하는 싱글 스레드 언어다. 즉, 한 번에 단 하나의 태스크만 처리할 수 있다.

하지만 실제 브라우저 환경을 보면 화면 애니메이션이 동작하면서 동시에 서버와 HTTP 통신을 하고, 사용자 클릭 이벤트까지 지연 없이 받아낸다.

싱글 스레드인 자바스크립트가 어떻게 여러 작업을 동시에 처리하는 것처럼 동작할 수 있는지, 브라우저 런타임 구조와 이벤트 루프(Event Loop)를 통해 알아보자.

자바스크립트는 외팔이 요리사다. 손이 하나뿐이라서 한 번에 프라이팬 하나만 잡을 수 있다. 라면을 끓이면서 동시에 계란후라이를 못한다.

그런데 식당을 보면 주문도 받고, 음악도 듣고, 요리도 척척 동시에 돌아간다.
손이 하나뿐인 요리사가 어떻게 이걸 다 하는지 주방 구조를 들여다보자.

자바스크립트 엔진의 내부 구조

자바스크립트 엔진(V8 등)은 크게 두 가지 메모리 공간으로 나뉜다.

  • 콜 스택 (Call Stack):
    • 함수가 호출되면 함수 실행 컨텍스트가 순차적으로 쌓이고(Push), 위에서부터 순서대로 실행된 뒤 제거(Pop)되는 공간이다.
    • 자바스크립트 엔진은 단 하나의 콜 스택만 사용하므로, 최상위 실행 컨텍스트가 종료되기 전까지는 그 어떤 작업도 끼어들 수 없다.
  • 힙 (Heap):
    • 객체나 배열처럼 크기가 동적으로 변하는 참조 타입 데이터가 저장되는 메모리 공간이다.
    • 구조화되어 있지 않은 자유 메모리 영역이며, 콜 스택의 실행 컨텍스트들은 이 힙에 할당된 객체의 주소값을 참조한다.

자바스크립트 엔진 자체는 단순하다. 요청받은 코드를 평가하고, 콜 스택에 올린 뒤 순서대로 하나씩 실행하는 것이 전부다. 스스로 타이머를 재거나 네트워크 패킷을 기다리는 기능은 엔진 내부에 없다.

도마 (Call Stack): 지금 당장 칼질해야 하는 재료들이 스택구조로 쌓이는 곳.
냉장고 (Heap): 양파, 소스, 고기처럼 덩치 크고 잡다한 재료들을 아무렇게나 쑤셔 박아둔 창고임. 도마 위에서 칼질할 재료가 있으면 여기서 주소만 보고 꺼내다 쓴다.

브라우저 런타임의 동시성 지원 메커니즘

비동기 작업에서 소스코드의 실행을 제외한 대기, 스케줄링, 통신 등의 부가 작업은 엔진 바깥의 런타임 환경인 브라우저(또는 Node.js)가 담당한다.

브라우저는 멀티 스레드로 동작하며, 엔진과 연동하기 위해 다음 두 가지 요소를 제공한다.

  1. Web APIs: 타이머 설정(setTimeout), 네트워크 요청(fetch), 이벤트 리스너 등록 등 시간이 걸리는 비동기 처리를 브라우저 백그라운드 스레드에서 대신 수행한다.
  2. 태스크 큐 (Task Queue / Callback Queue): 비동기 작업이 완료된 후 실행되어야 할 콜백 함수나 이벤트 핸들러가 일시적으로 대기하는 줄(Queue)이다. FIFO(선입선출) 구조로 동작한다.

식당의 도우미들(Web API 와 브라우저)
타이머와 알바생(Web API): 요리사가 라면 물을 올려놓고 3분간 멍하니 기다리면 주문이 밀린다. 그래서 요리사는 알바생한테 "3분 뒤에 알려줘!" 하고 냄비를 맡긴 뒤, 도마에서 다시 채소를 썬다.

주문 대기표 꽂이(태스크 큐): 3분 뒤에 알바생이 요리사를 바로 귀찮게 쳐서 알려주는 게 아니라. 대기표 꽂이에 먼저 온 순서대로 꽂아준다.

이벤트 루프의 역할

이벤트 루프는 브라우저(또는 Node.js)에 내장된 장치로, 콜 스택과 태스크 큐를 끊임없이 순회하며 감시하는 역할을 한다.

  • 동작 규칙:
    1. 현재 콜 스택에 실행 중인 실행 컨텍스트가 남아있는지 확인한다.
    2. 콜 스택이 완전히 비어있다면, 태스크 큐에서 대기 중인 첫 번째 콜백 함수를 꺼내 콜 스택으로 푸시(Push)한다.
    3. 콜 스택으로 올라간 콜백 함수가 비로소 자바스크립트 엔진에 의해 실행된다.

즉, 아무리 비동기 타이머가 끝나 콜백 함수가 태스크 큐에 도착했더라도, 콜 스택에 실행 중인 동기 코드가 단 하나라도 남아있다면 콜백 함수는 절대로 실행되지 못하고 대기한다.

주방의 매니저(이벤트 루프): 매니저의 규칙은 단 하나다. 요리사의 도마를 힐끔 힐끔 보다가 요리사가 아직 칼질 중이면 절대 방해 안한다. 도마가 깨끗하게 비는 순간 대기표 꽂이(태스크 큐)에 꽂혀 있던 주문을 잽싸게 낚아서 요리사 도마 위에 올려놓는다. 요리사는 그거보고 요리를 시작한다.

참고문헌 - 이웅모, 『모던 자바스크립트 Deep Dive 』, 위키북스(2020)

profile
Developer

0개의 댓글