자바스크립트에 동시성을 부여하는 이벤트 루프
Single Thread
자바스크립트 엔진은 한 번에 단 한 가지의 일만 수행 가능한 싱글 스레드(Single thread) 방식으로 동작합니다. 그렇다면 setTimeout과 같은 비동기 함수들은 어떻게 논블로킹 방식으로 처리되는 걸까요? 만약 싱글 스레드로 처리된다 하면, 비동기 함수가 실행을 마칠 때까지 블로킹되면서 프로그램이 멈췄을 텐데 말이죠.
이런 자바스크립트 엔진에 동시성(Concurrency)을 지원하기 위해 웹 브라우저는 이벤트 루프(Event Loop)라는 것을 지원합니다. 우리가 비동기 작업을 위해 사용했던 setTimeout과 setInterval 함수는 ECMA Script의 기본 사양이 아닌 웹 브라우저에서 별도로 제공하는 Web API입니다. 물론 기본적으로 소스 평가 과정을 거쳐 실행 컨텍스트로 올라가는 것은 동일하지만, 비동기 동작을 위한 타이머 정보(호출 시간, 콜백 함수)는 웹 브라우저에 의해 관리됩니다.
웹 브라우저 안에는 이벤트 루프와 함께 두 가지의 태스크 큐가 동작하고 있습니다.
- 태스크 큐: 비동기 처리를 위해 등록된 콜백 함수들이 잠시 대기하는 공간
- 마이크로 태스크 큐: 프로미스의 후속 처리를 위해 등록된 콜백 함수들이 잠시 대기하는 공간
- 이벤트 루프: 호출 스택이 비어있을 때, 태스크 큐에 등록된 콜백 함수를 콜 스택에 옮기는 작업을 수행
이벤트 루프는 호출 스택(Call Stack)과 태스크 큐를 계속 지켜 보면서, 호출 스택이 비어있을 때 태스크 큐에 등록된 콜백 함수들을 호출 스택에 순차적으로 옮깁니다. 만약 마이크로 태스크 큐에 콜백 함수가 있다면, 태스크 큐보다 우선적으로 참조합니다. 이처럼 태스크 큐와 이벤트 루프를 갖고 있는 웹 브라우저와 자바스크립트 엔진의 협업에 의해 우리는 자바스크립트에서도 비동기 함수를 사용할 수 있는 것입니다.
Node.js도 웹 브라우저처럼 이벤트 루프를 지원하지만, 내부 동작 방식에 약간 차이가 있습니다.
동시성? 블로킹?
위의 글을 읽어보면 동시성이니 블로킹이니 하는데, 이 용어들을 처음 보면 어떤 뜻을 가지고 있는지 모릅니다. 저도 그랬고요. 그래서 이벤트 루프와 함께 이들 용어에 대해서도 간단하게나마 알아보도록 할게요.
- 동시성(Concurrency): 한 번에 여러 일을 처리하는 것처럼 보이지만, 돌아가면서 처리하는 것
- 병렬성(Parallelism): 실제로 한 번에 여러 일을 처리하는 것
그리고 블로킹, 논블로킹이 나오면 동기, 비동기라는 용어도 늘 함께 언급되기에 같이 정리하겠습니다.
- 블로킹(Blocking): 함수를 호출하면, 제어권을 함수에게 넘기며 대기하는 방식
- 논블로킹(Non-Blocking): 함수를 호출해도 제어권을 넘기지 않고, 그대로 코드 흐름을 이어가는 방식
- 동기(Synchronous): 함수를 호출하고 나서 종료될 때까지 호출자(Caller)가 종료 여부를 신경 쓰는 방식
- 비동기(Asynchronous): 함수를 호출할 때 매개변수로 콜백 함수를 보내며, 호출자가 종료 여부를 신경 쓰지 않고 콜백 함수가 신경 쓰는 방식
블로킹은 동기와, 논블로킹은 비동기와 대부분 함께 하기 때문에 묶어서 이해해도 좋지만, 의미가 조금씩 다르기에 되도록이면 차이를 이해하고 있는 것이 좋습니다. 아래 그림은 블로킹과 동기가, 논블로킹과 비동기가 조합되었을 때의 동작을 나타낸 것입니다.
자바스크립트는 싱글 스레드이지만, 이벤트 루프를 기반으로 한 논블로킹-비동기 언어입니다. 👏
움짤로 확인하는 이벤트 루프
Dev.to 사이트에 Lydia Hallie님이 작성하신 글을 그대로 가져왔습니다.
자바스크립트 엔진의 소스 평가 과정을 통해 greet와 respond 함수가 호출 스택에 등록되고, 런타임 과정에 의해 순차적으로 실행됩니다. greet 함수를 실행해서, Output에는 "Hello"라는 내용이 먼저 출력됩니다.
이어서 respond 함수를 실행하는데, 이 함수는 setTimeout 함수를 반환합니다. setTimeout은 웹 브라우저에서 제공하는 Web API입니다. setTimeout 함수가 런타임 중에 실행되는 것은 일반 함수와 동일하지만, 매개변수로 사용된 타이머 정보나 콜백 함수는 웹 브라우저에 의해 관리됩니다.
setTimeout 함수의 매개변수로 지정해 둔 시간이 지나면, 브라우저는 콜백 함수를 태스크 큐에 등록합니다.
이벤트 루프는 호출 스택이 비어있는 것과 태스크 큐에 콜백 함수가 있는 것을 감지하여, 태스크 큐에 있는 콜백 함수를 순차적으로 호출 스택에 옮깁니다. 그림에는 없지만 프로미스를 관리하는 마이크로 태스크 큐도 있으며, 태스크 큐보다 마이크로 태스크 큐를 우선으로 합니다.
이렇게 콜백 함수가 호출 스택에 등록되어 실행됨으로써, 모든 동작이 마무리되고 프로그램이 종료됩니다.
References
'🌈 기술스택 > JavaScript' 카테고리의 다른 글
마우스로 터치 스크롤 구현하기 (1) | 2022.01.04 |
---|---|
비동기 처리를 위한 문법 (Promise) (0) | 2021.10.08 |
연속으로 발생하는 이벤트를 제어하는 방법 (0) | 2021.10.07 |
코드 실행에 필요한 정보를 담은 실행 컨텍스트 (0) | 2021.10.05 |
자기 자신을 가리키는 값 this (0) | 2021.10.03 |
댓글
이 글 공유하기
다른 글
-
마우스로 터치 스크롤 구현하기
마우스로 터치 스크롤 구현하기
2022.01.04 -
비동기 처리를 위한 문법 (Promise)
비동기 처리를 위한 문법 (Promise)
2021.10.08 -
연속으로 발생하는 이벤트를 제어하는 방법
연속으로 발생하는 이벤트를 제어하는 방법
2021.10.07 -
코드 실행에 필요한 정보를 담은 실행 컨텍스트
코드 실행에 필요한 정보를 담은 실행 컨텍스트
2021.10.05