Event Loop, Call Stack 이 작동하는 법

수경, Sugyeong·2022년 1월 7일
2

JavaScript

목록 보기
16/18
post-thumbnail

1. 개요

자바스크립트가 비동기 적으로 프로그래밍 될 때 그것이 어떻게 실행 되는지를 알아보는 유튜브 강의 를 들으며 정리한 내용을 블로그로 남기고자 한다. 나를 위해서도, 해당 지식과 개념에 대한 이해가 필요하신 분들을 위해서 기록을 남겨본다.

가장 쉬운 웹개발 with Boaz 님께서 Medium 블로그를 기반으로 설명해주신 영상을 참고하였다. 정말 친절하고 자세하게 설명해주셔서 처음 접하는 나도 이해가 잘 되었고 그것을 토대로 함께 스터디 하는 팀원분들에게 지식 공유도 하는 시간도 갖게 되었다.

2. 블로킹 & 논블로킹

자바스크립트는 싱글 스레드이다. 싱글 스레드를 검색해보면 논블로킹이라는 키워드가 따라다닐 것이다. 블로킹을 하게 되면 작업 1이 끝나기 전까지는 작업 2를 할 수가 없다. 이렇게 된다면 유저가 사용하는 데 있어 불편함을 느낄 것이다. 그래서 자바스크립트는 논블로킹으로 작업하게 된다. 예를 들어 작업 1이 클릭이라는 이벤트고, 작업 2가 이미지 로드라면 클릭을 하고 이미지 로드가 문제 없이 실행되게 된다.

이미지 출처 - 네이버 블로그

3. 논블로킹이 동작하는 방법과 그 구조

3.1 JS 엔진

그렇다면 논블로킹이 어떻게 동작하는 지 구체적으로 알아본다. 위의 이미지에서 JS는 JS 엔진을 의미한다. 우리가 JS 파일을 사용하게 되면 해당 파일은 사람이 작성한 것이기 때문에 컴퓨터는 알아 들을 수 없다. 그것을 기계어로 번역해주는 것이 JS 엔진이다. JS 엔진이 하는 일Memory Heap 과 Call Stack 을 사용해서 우리가 작성한 JS 파일을 기계어로 변환하여 컴퓨터가 실행할 수 있도록 한다.

3.2 Memory Heap & Call Stack

Memory Heap우리가 선언한 변수들이 어디에 저장 되어있는 지를 기록하는 저장 장소이다.

Call Stack 은 말 그대로 이해하자면 Call 이 Stack 처럼 쌓이는 Stack 이다. Stack 은 Data Structure 중 하나이며 First-in-Last-Out 의 형태로 실행 된다. Call 은 Function 을 호출하는 것을 의미한다. 우리는 Call Stack 을 통해서 어떤 함수를 실행하고 있는지 혹은 JS 파일의 어떤 부분이 실행되고 있는 지를 알 수 있다.

3.3 브라우저 상에서의 API 사용

JS 파일이 실행되는 환경은 다양한데 Node.js 와 같은 OS 상에서 실행 될 수도 있고 브라우저 상에서도 실행될 수 있다. 위의 이미지가 처리 되는 곳은 브라우저 인데 브라우저 상에서 실행된다는 것은 브라우저가 제공하는 API 들이 있고 API를 사용할 수 있다는 뜻이다. API 에는 종류가 많으나 대표적으로는 DOM (document), AJAX (XMLHttpRequest), Timeout(setTimeout) 이 있다.

3.4 Event Loop & Callback Queue

Event Loop 는 자바스크립트의 Event driven 이라는 말이 있다. Event 단위로 실행 되어진다는 의미로 해석하면 된다.

Callback Queue말 그대로 Callback 이 Queue 처럼 쌓인다는 뜻이다. Queue도 마찬가지로 Data Structure의 한 종류이다. 하지만 위에서 살펴본 Call Stack 과 다른 점은 First-in-First-Out 의 형태로 실행 된다. Callback 은 Function인데 다른 Function 에게 인자로 전달되어진 Function 이다. 따라서 Callback Queue 는 인자로 전달 되어진 Function 이 Queue 처럼 쌓여있다고 이해할 수 있다.

그렇다면 위의 이미지의 구조가 블로킹, 논블로킹의 작업을 처리하는 구조와 어떤 연관이 있을까? 각 작업을 하나의 Function 이라고 생각하면 된다. 논블로킹에서 작업 1이 실행되는 동안 작업 2가 실행되는데 실행되는 곳이 Web API 이다. 그리고 Web API 에서 실행되고 난 것을 Callback Queue 로 받아주고 Event Loop 가 Call Stack 으로 던져준다.

4. 예시

아래는 예시이다. 코드를 실행시키고 무슨 일이 있는지 확인해본다.

1. The state is clear. The browser console is clear, and the Call Stack is empty.

그야말로 텅 비어있는 상태이다. 브라우저 콘솔도, 콜스택도 모두 비어있다.

2. console.log('Hi') is added to the Call Stack.

함수 console.log('Hi') 가 콜스택에 찍히게 된다.

3. console.log('Hi') is executed.

브라우저 콘솔에 Hi가 출력된다.

4. console.log('Hi') is removed from the Call Stack.

실행이 된 함수인 console.log('Hi') 가 스택에서 빠져나가게 된다. Call Stack 에 어떠한 함수도 남아있지 않게 된다.

5. setTimeout(function cb1() { ... }) is added to the Call Stack.

setTimeout Function 도 마찬가지로 함수이기 때문에 Call Stack 에 쌓인다.

6. setTimeout(function cb1() { ... }) is executed. The browser creates a timer as part of the Web APIs. It is going to handle the countdown for you.

setTimeout Function 은 실행이 되면 Web API 를 호출하게 되는데 Web API 중 Timer API 를 호출한다. setTimeout 에 두 번째로 넘겨준 숫자 인자 5000ms 만큼을 Timer 로 재서 그 시간이 지나고 나서야 첫 번째로 넘겨준 함수인 console.log('cb1') 을 실행하게 된다.

7. The setTimeout(function cb1() { ... }) itself is complete and is removed from the Call Stack.

콜스택에서 실행이 된 함수는 콜스택에서 빠져나가기 때문에 아래 이미지와 같이 빈 콜스택이 보이게 된다.

8. console.log('Bye') is added to the Call Stack.

콜스택이 비어있기 때문에 바로 다음 함수인 console.log('Bye') 가 들어오게 된다. 콜스택이 비어 있다면 입력 했던 코드 한 줄 한 줄 순서대로 Function 들이 들어오기 때문이다. 자바스크립트는 콜스택을 비우고 싶어하기 때문에 콜스택 내부의 console.log('Bye') 를 실행 시켜준다.

9. console.log('Bye') is executed.

console.log('Bye’) 가 실행이 되어 브라우저에 찍혀있다.

10. console.log('Bye') is removed from the Call Stack.

console.log('Bye’) 가 실행이 되었으니 역시 콜스택에서 빠져나간다.

11. After at least 5000 ms, the timer completes and it pushes the cb1 callback to the Callback Queue.

Timer 의 등록된 시간 5000ms 이 다 지나면 콜백함수 'cb1' 이 Callback Queue 안으로 들어오게 된다.

12. The Event Loop takes cb1 from the Callback Queue and pushes it to the Call Stack.

Event loop 는 콜스택을 계속 보고 있다가 콜스택이 텅 비게 되면 Callback queue 에 있던 콜백함수 'cb1' 을 콜스택으로 전달해준다. Event Loop 의 돌아가는 아이콘의 의미는 Callback 과 콜스택을 항상 보고 있다는 의미이다.

13. cb1 is executed and adds console.log('cb1') to the Call Stack.

콜백함수 'cb1' 이 실행 되고 그 안에 있던 console.log('cb1') 을 다시 실행하게 된다. 여기서 주목해야 할 점은 콜스택에 Stack 이 쌓여 있다는 점이다. 아직 콜백함수 'cb1' 이 종료되기 전에 다른 Function 인 console.log('cb1’) 를 Call 했기 때문에 콜백함수 'cb1' 위에 console.log('cb1’) 이 쌓이게 된다.

14. console.log('cb1') is executed.

브라우저 창에 console.log('cb1') 이 실행이 되어 찍히게 된다.

15. console.log('cb1') is removed from the Call Stack.

콜스택에서 console.log('cb1’) 은 사라지게 된다.

16. cb1 is removed from the Call Stack.

콜백함수 'cb1' 도 빠져나가게 된다.

4. 결론

자바스크립트가 어떻게 비동기적인 프로그래밍을 처리하는지를 JS 엔진의 한 요소인 Call Stack, Web API, Callback Queue, Event Loop 을 통해 구체적으로 알아보았다. ES6 에서는 Callback Queue에 추가로 Promise 가 등장하였으며 Promise 를 처리하는 방식은 위와 방식이 다르다고 한다. Promise 와 Promise 의 처리 방식을 이해하기 위해서는 Callback 이 어떻게 비동기를 처리하는 지에 대해 배워야한다고 한다.

우리가 코드를 작성하고 그 코드들이 실행이 되어 화면에 출력되는 그 짧은 찰나 속에서 위와 같은 과정이 이루어지고 있었다. 우리가 화면에 찍어보던 console.log 도, 함수도 어떤 과정을 거쳐서 육안으로 확인할 수 있는 화면에 출력되는지 잘 알게 되었다.

1개의 댓글

comment-user-thumbnail
2023년 5월 23일

감사합니다!!

답글 달기