염딩코

[JS] Event loop 본문

Front-End/Javascript

[JS] Event loop

johnyeom 2023. 8. 3. 02:52

 

자바스크립트는 싱글 스레드 기반 언어이다.

Non-blocking 방식의 비동기적인 동시성 언어이며 콜 스택, 이벤트 루프와 콜백 큐, 그리고 여러가지 다른 API들을 가지고 있다.

 

 

자바스크립트 엔진인 V8은 콜 스택과 힙을 가지고 있다. 

  • 힙은 메모리가 할당되는 부분
  • 콜 스택은 함수가 호출될 때, execution context가 쌓이는 영역

콜 스택(Call Stack)

그림을 보면, 자바스크립트 엔진인 V8이 가지고 있는 힙과 콜 스택이 있고, 

웹 브라우저에서 제공하는 Web API가 DOM, Ajax, setTimeout 등을 제공하는 것을 알 수 있다.

하단에는 event loop와 콜백 큐가 있는 것을 확인할 수 있다.

 

하나의 스레드 = 하나의 콜 스택 = 한 번의 한 작업

 

자바스크립트는 Single thread 언어이기 때문에 한 번에 하나의 작업을 하는 것을 알 수 있다.

즉, 한 번의 하나의 콜 스택을 가질 수 밖에 없다는 것을 의미한다.

 

아래와 같은 코드가 있다고 하자.

function addition(a,b) {
	return a+b;
}

function func2(n) {
	return addition(n, n);
}

function printResult(n) {
	const num = func2(n);
	console.log(num);
}

printResult(5);

 

위의 코드를 실행하면 stack에는 다음과 같이 쌓인다.

Stack
addition()
func2()
printResult()
main()

가장 처음에는 main함수의 execution context가 추가된다. 

이런 방식이 기본적인 콜 스택이며 웹 브라우저에서 에러가 발생했을 때, 그때까지의 호출 순서를 보여주는 것도 콜 스택을 통해서 하는 것이다.

만약 콜 스택을 재귀함수로 호출하게 되면 아래와 같은 경고문가 나오면서 종료한다.

 

RangeError: Maximum call stack size exceeded!

 

 


그렇다면 이벤트 루프와 콜백 큐는 뭘까?

 

이벤트 루프와 콜백 큐에 대해서 알아보기 전에 블로킹에 대한 내용을 먼저 알고 넘어가자.

2023.07.27 - [Front-End/Javascript] - [JS] 블로킹과 논블로킹 / 동기와 비동기

 

[JS] 블로킹과 논블로킹 / 동기와 비동기

오늘은 블로킹과 논블로킹 그리고 동기와 비동기에 대해서 배워봅시다! 그리고 이들이 서로 어떻게 연관되어 있는지 알아봅시다! 블로킹과 논블로킹, 동기와 비동기에 대해서 공부하기 전에 먼

yeomyeom.tistory.com

블로킹에 대해서 간단히 말하자면 "느리게 동작하는 방식"이라 말할 수 있다.

MDN 공식 문서에 따르면 자바스크립트는 절대 블로킹 연산을 하지 않는다고 나와있다.

자바스크립트에서는 느리게 동작하는 방식을 사용하지 않고, "비동기 콜백" 이라는 방식을 사용한다.

 


비동기 콜백(Asynchronous Callback)

일반적으로 비동기 콜백을 설명할 때, 가장 많이 사용하는 함수가 바로 setTimeout 이다.

이 함수는 주어진 시간만큼 기다린 후 콜백 함수를 실행한다.

setTimeout은 V8에 내장돼 있지 않고, 웹 브라우저에서 제공하는 Web API에 존재한다.

 

아래의 코드를 보면서 비동기 콜백이 어떻게 이루어지는지 알아보자.

console.log('stack 1');

setTimeout(function callback() {
	console.log('Asynchronous Callback');
}, 3000);

console.log('stack 2');

지금까지 배운 콜 스택의 개념을 활용하면 콜 스택에 차례대로 쌓일 것 같지만,

V8의 소스코드에는 setTimeout 함수가 없기 때문에 웹 브라우저가 대신 실행해줘야 한다.

여기서 바로 "동시성" 개념이 나온다.

즉, 자바스크립트는 싱글 스레드 기반임에도 불구하고 동시성 언어라고 불리는 이유는

웹 브라우저가 제공하는 API를 통해 동시에 작업을 할 수 있기 때문이다. 

 

 

 

처음에는 순서대로 쌓이다가 setTimeout 함수를 웹 브라우저에게 맡기고 두 번째 log를 쌓는다.

따라서 아래와 같이 먼저 출력된다.

stack 1
stack 2

이제 콜 스택에서 main()을 제외한 모든 함수가 리턴되고 Web API의 setTimeout 타이머가 종료되면 해당 콜백이 콜백 큐로 전달된다.

이제 여기서 이벤트 루프의 역할이 나오는데

 

이벤트 루프는 콜 스택과 콜백 큐를 감시하는 역할로 콜백 큐에 함수가 존재하고 콜 스택이 비었다면 콜백 큐에서 콜백을 꺼내 콜 스택에 넣어주는 역할을 한다.

 

아래의 그림을 보고 이해해보자.

 

이벤트 루프의 역할

따라서 아래의 코드는 다음과 같은 결과를 출력한다.

console.log('stack 1');

setTimeout(() => console.log('stack 3'), 0);

console.log('stack 2');



// stack 1
// stack 2
// stack 3

 

 

웹 브라우저가 담당했던 setTimeout 함수가 콜백 큐로 가고, 다음에 이벤트 루프가 콜백 큐에서 콜 스택으로 옮기는 과정을 거치기 때문이다.

그래서 setTimeout을 연속으로 호출하는 경우 또한 기대하는 지연시간과 다른 값이 나올 수 있다.

'Front-End > Javascript' 카테고리의 다른 글

[JS] 생성자 함수에 의한 객체 생성  (0) 2023.08.05
[JS] Property Attribute  (0) 2023.08.05
[JS] Prototype  (0) 2023.07.31
[JS]let, const 키워드와 블록 레벨 스코프  (0) 2023.07.29
[JS]전역 변수의 문제점  (0) 2023.07.29