본문 바로가기

Frontend/JavaScript

자바스크립트와 이벤트 루프(Event Loop)

Event Loop

function a(){
    setTimeout(function(){
        console.log("first");
    }, 0);

    for(let i=0; i<100000; i++){}

    console.log("second");

}

a();

Q. 왜 second → first의 순서로 작동이 되는가?

A. Event Loop 때문이다.


자바스크립트는 싱글 스레드(single-thread)이다. 그렇다면 하나의 스레드밖에 없기 때문에 한 번에 한 동작만 실행될 수 있다고 생각할 수 있으나, 그렇지 않다. 우리가 흔하게 볼 수 있는 웹페이지를 몇 개만 둘러봐도 마우스 클릭을 하면 애니메이션 효과도 보여주고 동시에 마우스 클릭 이벤트를 처리하는 페이지들을 심심찮게 볼 수 있다. 이것이 바로 자바스크립트의 동시성(Concurrency)이다.

그렇다면 자바스크립트의 동시성을 어떻게 지원하는가?라는 궁금증이 들게된다. 이때 등장하는 중요한 개념이 바로 이벤트 루프(Event Loop)이다.

V8

이벤트 루프를 설명하기 전에, V8에 대해 간단하게 설명하고자 한다. V8은 자바스크립트를 동작할 수 있게 하는 자바스크립트의 대표적인 엔진으로, 크롬, node 등에서 사용 중이다.

→ 자바스크립트의 동작원리 = 자바스크립트 엔진(V8(크롬, node에서 사용) 등)

자바스크립트의 구조

위 그림은 자바스크립트의 구조를 나타내는 사진이다.

Heap&Call Stack

방금 언급한 V8과 같은 자바스크립트 엔진의 구성요소이다.

  • Heap : 자바스크립트의 객체의 주소값, 구조화되지 않은 메모리 영역이 쌓인다.
  • Call Stack : 일반적으로 우리가 호출하는 함수들이 쌓인다.

Web API

  • Web API : 브라우저에서 제공되는 API. 비동기 작업을 실행하며 결과를 Task Queue에 넘겨준다.

Task Queue

  • Task Queue : Stack이 비어있어야 실행된다. 그전까지는 Event Loop를 돈다.

여기서 정말 중요한 개념이 나왔다. Task Queue는 Stack이 비어있기 전까지 Event Loop를 돌며 Stack이 비었나 확인한다. 비어있지 않으면 Queue 안의 API들을 내보내지 않는다.

아래 코드는 MDN에서 제공하는 Event Loop의 가상코드이다.

while (queue.waitForMessage()) {
    queue.processNextMessage();
}

아까 처음 나온 코드로 이 개념을 적용해서 설명하면 아래처럼 된다.

function a(){
        setTimeout(function(){
            console.log("first");
        }, 0);

        for(let i=0; i<100000; i++){}

        console.log("second");

    }

a();
  1. 이벤트 루프는 계속 돌아가고 있다.

  1. a()가 Call Stack에 들어간다.

  1. setTimeout function이 Call Stack에 들어갔다 Web API로 옮겨진다.

  1. Web API에서 콜백되어 Task Queue에서 받는다.

  1. for문이 Call Stack 안으로 들어가서 돈다.

  1. for문이 끝나면 Call Stack에서 제거되고, "second"를 출력하는 console문을 실행한다.

  1. "second" → a() 순으로 Call Stack에서 삭제가 되고, Stack에 아무것도 남지 않으니까 Task Queu의 setTimeout 함수("first" 출력)를 실행한다.

이외에도 더 많은 예제를 시각적으로 확인하고 싶으면

http://latentflip.com/loupe 에서 이벤트루프를 시각적으로 확인할 수 있다.

CPU intensive

자바스크립트가 싱글 스레드이지만 다중 입출력이 매우 빠른 이유는 Event Loop 때문이다.

하지만 스택에 불필요한 내용이 들어가서 Queue에 있는 내용이 실행을 못하게 되어 무한으로 Event Loop가 발생할 수도 있다.

이처럼 cpu intensive가 생기게 되면 성능이 매우 느려지기 때문에 주의해야 한다.

참고 문헌

Chrome V8 - Wikipedia

[JS] JavaScript의 Event Loop