브라우저 런타임 환경 – Event Loop

자바스크립트로 할 수 있는건 너무 한정적이다. 하지만 웹 APIs 를 이용하여 다양한 것들을 할 수 있다 ! 웹 APIs 는 브라우저에서 제공하는 API이기 때문에 브라우저의 멀티쓰레딩을 이용해서 다양한 일들을 동시에 실행할 수 있다.
(예를 들어 fetch를 이용하여 백엔드에서 데이터를 받아온다던지, setTimeout을 이용하여 등록한 콜백함수를 실행한다던지… 🙂 )


자바스크립트 엔진에는 함수들을 담을 수 있는 콜 스택이 있어 순서대로 일을 처리할 수있지만, web APIs를 통해 등록한 콜백함수는 어떻게 동작하는걸까? 어떻게 웹 APIs와 자바스크립트 엔진이 서로 일을 할 수 있는걸까? 🤔

그럼 웹 APIs 와 자바스크립트 엔진이 어떤식으로 대화를 하고 서로 협력하면서 일들을 수행해나가는지 알아보자 😤


예를 들어 second() 에서 setTimeout을 호출하고, 콘솔에 ‘hello’를 출력하는 콜백함수를 등록했다고 가정해보자.

  • main() > first() > second() > setTimeout() 순으로 Call Stack에 쌓임

setTimeout을 호출하는 순간 setTimeout은 Call Stack에서 지워지고, 웹 API는 타이머를 시작하게 된다.

  • setTimeout이 호출되면, 엔진의 Call Stack에서 setTimeout 이 지워지고, 웹 API는 타이머를 시작한다.
  • setTimeout에서 지정된 시간이 끝나면 웹 APIs는 Task Queue에 호출시 등록한 콜백함수를 집어넣는다. (타이머가 실행되고 있는 동안에도 자바스크립트 엔진은 병렬적으로 실행된다.)

✏️ 여기서 Queue란 ?

보통 자료구조의 stack 다음에 배우는 자료구조의 하나로서, FIFO(First In First Out) 구조를 갖는다.

그럼 아직 Call Stack에 first(), main() 함수가 남아있는 시점에서, Task Queue에 들어가있는 저 콜백함수는 언제 실행될까 ?

이런 Task Queue와 Call Stack을 계속해서 관찰하면서 실행을 조율하는 친구가 Event Loop 이다.

결과부터 말하자면, main()까지 모두 끝나고 난 다음 등록한 콜백함수가 호출된다.

즉, 이벤트 루프는 계속 Call Stack과 Task Queue 를 체크하면서 콜 스택이 비워질때까지 기다린다. 콜 스택이 비워지고 자바 스크립트 엔진이 더 이상 일을 하고 있지 않을때, 이벤트 루프가 Task Queue에 있는 콜백 함수를 Call Stack으로 가져와서 엔진이 함수를 수행할 수 있도록 도와준다.


또 다른 예로 버튼에 클릭 이벤트 리스너를 등록하고 브라우저에서 버튼 클릭 이벤트가 발생하게되면, 웹 APIs는 Task Queue에 버튼 클릭시 동작할 함수(콜백 함수)를 넣어둔다. 이벤트 루프는 콜 스택이 비워질때까지 기다렸다가 클릭에 대한 콜백함수를 콜 스택에 넣어준다.

클릭이 만약 여러번 된다면 Task Queue에 콜백함수가 여러번 쌓이는데, 콜 스택이 비었을때 한번에 큐에 있는 모든 콜백함수를 콜 스택에 쌓는게 아닌, 한번에 하나씩만 쌓는다.

즉, 이벤트 루프는 click에 대한 콜백함수 하나를 Call Stack에 집어넣고, 그 콜백함수가 끝날때까지 기다렸다가 태스크 큐에서 다음 콜백함수를 가지고 온다.


✏️ 기억해둬야할 중요 포인트

  • Call Stack에서 수행중인 함수는 끝날때까지 보장이 된다. 즉 중간에 다른 일들을 할 수가 없다. (Event Loop가 끝날때까지 기다렸다가 콜백함수를 콜스택에 쌓기 때문)