Event Loop

augusstt·2023년 10월 11일
0

JS

목록 보기
10/14
post-thumbnail

최근 자바스크립트라는 언어에 대해서 공부를 하고 있는데 이번에는 이벤트 루프에 대해 공부해보려 한다.

시작하기 앞서서

이벤트 루프는 브라우저와 자바스크립트 런타임 환경 (Node js)에서 작업을 실행할때 사용되는 메인 스레드이다.
보통 "자바스크립트는 싱글 스레드 언어이다"라고들 하는데 그 이유가 바로 메인스레드인 이벤트 루프가 싱글스레드이기 때문이다.

그림을 보면서 이벤트루프가 어떻게 동작하는지 살펴보자

CallStack, Memory Heap

먼저 그림 왼쪽에 표시된 자바스크립트 엔진을 보자.
메모리 힙이라는 것과 콜스택이라는 것으로 이루어져 있다. 메모리힙은 메모리 할당이 일어나는 곳이고, 콜스택은 이름 그대로 실행코드가 하나씩 스택의 형태로 쌓이는 곳이다.

function multi(a,b){
  return a * b;
}
function square(n){
  return multi(n, n);
}
function printSquare(n){
  let squared = square(n);
  console.log(squared);
}
printSquare(3);

위의 코드를 실행하게 되면 먼저 모든 코드를 지칭하는 메인함수를 콜스택에 먼저 넣게 된다. 그러다가 가장 마지막줄에 함수를 호출하는 printSquare(4)를 만나게 되어 콜스택에 추가된다. 이후 square, multi를 차례로 호출하게 되어 콜 스택안에는 { main - printSquare - square - multi }의 순으로 쌓이게 된다.(스택의 형태이기 때문에 맨 위에 multi가 쌓여있다.)
이제 스택 맨 위에 있는 함수부터 return을 시키며 하나씩 스택에서 제거한다.


extra - Execution Context

사실 위의 표현에서 함수를 콜스택에 넣는다고 했는데 정확히 얘기하면 함수의 실행 컨텍스트 (Execution Context)를 생성하고 콜스택에 넣는 것이다. 마찬가지로 콜스택에서 제거될때도 함수실행 컨텍스트가 제거되는 것이다.

실행 컨텍스트를 여기서 다 다루면 이벤트 루프를 주제로 하는 포스팅에서 엇나갈것같아 간단히 설명 후 다른 포스팅에서 다루려고 한다.

실행 컨텍스트는 간단히 말하자면 자바스크립트가 실행되는 영역이다. 크게 3가지로 분리되는데

  • 전역실행 컨텍스트
    코드를 실행할때 최초로 생성되는 실행 컨텍스트이다. 코드내용이 없어도 전역객체인 window와 이를 가리키는 this가 생성된다. (브라우저에서 console.log(this)를 실행하면 Window 객체가 나오는 이유가 바로 이것이다.)

  • 함수실행 컨텍스트
    최초 코드 실행 이후 함수가 호출될때마다 각 함수별로 실행 컨텍스트를 생성된다. 따라서 함수가 호출되지 않으면 함수실행 컨텍스트는 생성되지 않는다.

    헷갈리면 안되는 점은 함수 선언이 아니라 실행시에 생성된다는 점이다.

  • Eval실행 컨텍스트


즉, 자바스크립트는 하나의Call Stack으로 동작하기 때문에 싱글스레드 언어라는 것을 알수 있다.

그런데 우리가 실제로 브라우저/Node js를 사용할때는 여러개의 스레드가 사용되는데 어떤식으로 작동하는지 살펴보자.

Event Loop

function hi(){
  return "hi!";
}
function respond(){
  return setTimeout(() => {
    return "Hello";
  }, 1000);
}

hi();
respond();

이전에 예시로 들었던 코드와 달리 setTimeout 함수가 등장하여 비동기 작업을 수행하는 코드이다. 실제로 브라우저상에서는 비동기로 요청하는 작업이 수없이 많다.

먼저 위 코드가 작동하는 과정을 살펴보자

  • hi 함수실행 컨텍스트와 respond함수실행 컨텍스트가 순서대로 콜스택에 쌓인다.

  • 하단의 실행구문으로 인하여 hi함수실행 컨텍스트가 먼저 콜스택에서 제거된다.

  • 다음으로 respond 함수실행 컨텍스트가 실행 후 콜스택에서 제거된다.

  • respond 함수 내의 setTimeout이라는 WebApi가 존재하므로 브라우저가 자바스크립트 엔진과 다른 스레드에서 해당 요청을 처리한다.

  • Web Api에서 setTimeout에 지정된 시간이 지난 후, 전달된 콜백함수는 Task Que 로 전달된다. (콜스택으로 전달되지 않는것이 핵심이다.)

  • 이후 만약 콜스택이 비어있다면 해당 함수실행 컨텍스트를 콜스택으로 전달하고 비어있지 않다면 전달하지 않는다.

  • 콜스택이 비어있으므로 함수를 콜스택으로 전달한 후 결과 출력이후에 제거된다.

Web Api, Task Que같은 새로운 개념이 등장했으니 먼저 해당 개념에 대해 공부해보자


Web Api

예시에서 나온 setTimeout을 포함하여 Ajax , Event Listener 처럼 웹브라우저에서 제공하는 기능들을 일컫는다.

과정 설명을 통해 언급한 것처럼 자바스크립트 엔진의 콜스택에서 비동기 함수가 실행되는 경우, 해당 함수가 요청하는 비동기 작업정보와 콜백함수를 Web Api를 통하여 브라우저에게 전달한다.
이후 브라우저는 전달받은 요청들을 별도의 스레드에 위임한 후, 요청이 완료됨과 동시에 Task Que에 전달한다.

Task Que

태스크큐는 웹 api로 부터 전달받은 콜백함수들을 큐의 형태로 저장한다. 웹 api와 달리 자바스크립트 엔진에 포함되어 있으며, 저장된 함수들은 콜스택이 비는 순간 차례대로 전달된다.
유의할 점은 콜스택이 비어있을때 전달되기 때문에, 지정(예상)한 시간보다 더 늦게 실행될 수도 있다.


이제 다시 예시코드의 동작과정을 살펴보자.

자바스크립트 엔진의 Call StackTask Que단일스레드로 동작하는 자바스크립트의 작업을 별도의 스레드에서 작업할수 있도록 도와준다.

조금 더 생각해보면 우리는 콜스택이 비어있는지, 태스크큐에 함수가 있는지를 지속적으로 확인을 해주어야 할 필요성이 있다. 확인을 지속적으로 해주지 않는다면 태스크큐에 있는 함수가 콜스택이 비어있음에도 불구하고 전달되지 않아 실행되지 않을수 있기 때문이다. 사용자 경험을 매우 중시하는 브라우저에서 이러한 현상은 치명적일 수 밖에 없다.

이 역할을 수행해 주는 것이 바로 Event Loop이다.
이벤트루프는 콜스택과 태스크큐를 지속적으로 보고 있다가 콜스택이 비워지는 순간 태스크큐에 있는 콜백함수를 전달시키는 역할을 한다.

전체적인 흐름에서의 동작을 다시 한번 살펴보면

  • 함수1, 함수 2(setTimeout)를 Call Stack에 삽입

  • 함수1을 실행 후 제거

  • 함수2에 setTimeout이 포함되어 있으므로 스택에서 제거하고 Web Api로 전달

  • Web Api에서 실행된 결과를 Task Que로 전달

  • Event LoopCall Stack을 확인하고 비어있으므로 Task Que ➡️ Call Stack으로 해당 함수 전달

  • 실행 후 제거

위와 같은 동작과정을 거치는 것을 확인할 수 있다.

정리

공부한 내용을 정리해보자면

자바스크립트는 단일 콜스택을 사용한다는 점에서 싱글 스레드 언어라고 할수 있다. 하지만 실제로 자바스크립트가 사용되는 환경인 브라우저나 Node js에서는 여러개의 스레드가 사용되는데, 다수의 스레드 환경과 단일 스레드 언어를 연동하기 위해서 Event Loop가 사용된다.

profile
Don't look back, just look forward and study 💻

0개의 댓글