js 이벤트 루프
전 게시글에선 js의 타이머 함수에 대해서 알아보았다.
이번엔 이런 실행의 기반이 되는 자바스크립트의 동시성 모델과 이벤트 루프에 대해서 정리하려 한다.
런타임 개념
- 함수 호출은 자바스크립트의 콜스택 위에 하나의 프레임을 만든다.
- 자바스크립트는 콜스택의 맨 위부터 하나씩 실행하며 실행 후에는 제거한다.
- 자바스크립트는 메시지 큐( 처리할 메시지의 대기열)을 사용한다.
큐에서 가장 오래된 메시지와 연결된 함수를 호출하여 실행 후 제거한다.
마찬가지로 새로운 스택 프레임도 생성된다.
실행환경과 자바스크립트
자바스크립트와 자바스크립트 실행환경(nodejs,브라우저)는 다른 구조를 갖고있다.
실행환경은 싱글스레드가 아니다
자바스크립트는 싱글스레드를 사용하지만 실제 실행환경은 멀티스레드로 실행된다.
브라우저 환경을 간략하게 그림으로 표현하면 다음과 같다.

위의 그림과 같이 비동기 호출을 위한 함수들은 webAPI 영역에 정의되어있다.
또한 이벤트 루프와 태스크 큐 등도 자바스크립트 엔진 외부에 구현되어있다.
nodejs또한 마찬가지이다.
자바스크립트 엔진
하지만 자바스크립트 엔진은 단일 호출 스택과 동시에 여러 함수를 실행할 수 없다.
자바스크립트 엔진에서의 함수 호출은 스택 프레임을 형성한다.
또한 스택의 모든 함수들이 실행을 마치고 스택에서 제거되기 전까지는 어떤 함수도 실행될 수 없다.
태스크 큐와 이벤트 루프
앞서 설명했듯이 실행환경은 멀티스레드로 동작하고 자바스크립트 엔진은 싱글스레드로 동작한다.
이벤트루프와 태스크 큐는 다른 방식으로 동작하는 실행환경과 자바스크립트 엔진이 상호작용하는 방법이다.
태스크 큐
코드가 실행되면 이 코드는 현재 실행중인 태스크가 된다.
코드를 실행하는 중에 호출된 함수들은 태스크 큐에 추가된다.
마이크로 태스크 큐
마이크로 태스크 큐는 일반 태스크보다 더 높은 우선순위를 갖는 태스크이다.
대표적으로 promise
의 then()
과 같은 메서드들은 태스크 큐가 아닌 마이크로 태스크 큐에 추가된다.
이벤트 루프
이벤트루프를 간략하게 나타내면 다음과 같다.
1 | while (queue.waitForMessage()) { |
waitForMessage는 현재 실행중인 태스크가 없을 때 다음 태스크가 큐에 추가될 때 까지 대기한다.
즉 현재 실행중인 태스크가 없는지
와 태스크 큐에 태스크가 있는지
를 반복적으로 확인한다.
현재 실행중인 함수의 실행이 다 끝나 호출스택이 비워지면 이벤트 루프는 다음과 같이 실행된다.
- 마이크로 태스크 큐가 비었는지 먼저 확인한다. 비어있지 않을 경우 마이크로 태스크 큐에 있는 콜백을 실행한다.( 호출스택에 추가한다.)
- 비어있을 경우 (일반)태스크 큐에 대기중인 가장 오래된( 맨 앞의 ) 태스크를 실행한다(호출스택에 추가한다.)
정리하자면 이벤트루프는 태스크 큐와 자바스크립트의 단일 호출 스택을 상호작용하게 해준다.
ref
Event Loop mdn
자바스크립트와 이벤트 루프
코드종 영상
Tasks, microtasks, queues and schedules