https://www.zeolearn.com/magazine/understanding-the-javascript-event-loop

 

Understanding the JavaScript event loop

Event Loop is one of the powerful aspects of JavaScript. This article clarifies and highlights how JavaScript works and what makes it weird when compared to languages that you might have previously used.

www.zeolearn.com

C++, Ruby등의 언어와는 다르게 자바스크립트는 싱글스레드 언어이다. 싱글스레드는 한번에 한가지 일을 하고 하나의 일을 할 때 다른 일을 하지 못 한다. 이게 또 물론 멀티스레드 데드락 같은 현상이 이러나지 않지만 복잡한 일을 하지 못하는 단점을 가진다. 

 V8엔진이라고 구글이 만든 자바스크립트 엔진이 있다. 브라우저에서 동작한다. JS엔진은 2가지 메인 컴포넌트로 구성 되어있는데 그게 Heap과 Call Stack이다.

Heap은 모든 메모리가 할당되는 장소이다. 

Call Stack은 기본적으로 데이터 구조이고 우리가 프로그래밍을 하는 장소를 기록한다. 그러니까 만약 프로그램에 실행 컨텍스트(ex/ function call)가 있다면 콜 스텍이 실행 컨텍스트를 스택에 넣고 리턴을 받을 때 다시 꺼내는 역할을 한다. 

콜스텍 내부에서 어떻게 동작하는지 보자

function multiply(a, b) {
   return a*b;
}

function square(a) {
   const sq = multiply(a, a);
   
   console.log(sq);
}

square(3); // 9

JS엔진은 힙안에 함수할당에 대한 메모리를 만든다.  읽어내리다 square(3)코드에 도달하면 js엔진은 이걸 콜 스텍에 집어 넣는다.

먼저 함수 multiply, square를 힙에 올리고 square함수가 콜스텍에 들어간다. square함수 내부의 변수 sq가 그 다음으로 콜 스텍에 들어가고 sq변수가 참조하고 있는 multiply함수가 실행된다. multiply가 실행되고 sq변수가 콜 스텍에서 빠지고 콘솔로그sq가 다음으로 콜 스텍에 들어간다. 콘솔로그 찍고 콜스텍에서 빠지고 마지막으로 모든걸 다 실행한 함수 square가 콜 스텍에 빠지고 코드가 끝난다. 콜 스텍은 FILO( First Input Last Out )이다.

각 콜스텍의 입구는 Stack Frame이라 부르고 우리는 콘솔(크롬 F12눌러 나오는 창에서 console부분)에서 이걸 확인할 수 있다.

function customError() {
   throw new Error("Print the stack trace from here!!");
}
function foo() {
   customError();
}
function bar() {
   foo();
}
bar();

위의 코드를 실행하면 콘솔에

Uncaught Error: Print the stack trace from here !!
	at customError (main.js:2)
    at foo (main.js:6)
    at bar (main.js:10)
    at main.js:13

위의 에러가 뜬다. 여기에 콜 스텍 순서(Stack Trace)를 볼 수 있다.

 

- Asynchronous 

setTimeout은 비동기 API이다. 보통 동기적으로 코드가 작동되면 콜스텍에 들어간 코드가 끝나야 다음 코드라인으로 넘어가는데 비동기는 이러한 코드들을 비 동기적으로 실행하게 한다.

console.log("a");

setTimeout(() => {
	console.log("b");
}, 500);

console.log("c");

위의 코드를 실행하면 a,b,c 순서대로 로그가 찍히지 않는다.

먼저 a 로그가 콜 스텍에 들어갔다 나오며 로그를 찍고 다음으로 b로그를 찍기 위해 setTimeout이 콜 스텍에 들어가지만 실행하지 않고 시간이 될때 까지 대기 상태가 된다. 이때 안 기다리고 바로 c가 콜스텍에 들어가 로그를 찍고 빠지고 시간이 다 되면 b가 다시 콜 스텍에 들어가 b로그를 찍는다.

대기 상태의 코드들은 queue에 들어가게 된다. 이게 비동기방식으로 작동하는 코드이다.

 

그런데 자바스크립트는 싱글스레드인데 어떻게 동시적으로 프로세스들이 실행될 수 있는지 궁금할거다. 브라우저는 Wep APIs, Callback Queue, Event Loop같은 것들로 구성 되어있는데 이게 JS런타임 보다 많은 일을 하게한다.

Wep APIs는 우리가 요청하는 스레드들이고 그 스레드들을 콜 스텍이 비어있을 때 프로세스들을 실행하게 해준다. 

V8 브라우저 엔진 구성요소

위에 처럼 생겼다.

 

아까 그 비동기 코드들을 브라우저 구성요소와 함께 보면 이렇다.

비동기 코드 실행

setTimeout같은 API들은 js런타임에 존재하는게 아니라 Web API에 의해 실행된다. 이게 callback과 함께 등록되며 타이머가 만료되면 event queue에 들어가고 이벤트 루프가 콜스텍이 비었을 때 이걸 콜스텍으로 보낸다. 대충 위의 구조로 작동된다.

Event Loop는 한가지 일을 하는데 그건 Call Stack과 Callback Queue를 지켜보는 거다. 콜 스텍이 비어있을 때 이벤트 루프는 큐에 있는 첫 번째 이벤트를 갖고 스텍으로 보내준다. 이게 다다.

 

 

 

+ Recent posts