티스토리 뷰

AWS Lambda 의 context 객체에는 callbackWaitsForEmptyEventLoop 라는 프로퍼티가 있다.

저녀석에 대해 알아보다가 이참에 자바스크립트의 이벤트 루프에 대해 정리해보려 한다.

(이번에 다루는 것은 Node.js 의 libuv에 대한 얘기는 아니다.)

 

 

시작하기에 앞서 자바스크립트의 동작 원리에 대해 정리해보자.

 

일반적으로 자바스크립트를 사용하고있는 브라우저에는 크게 2가지 엔진이 있다.

1. 자바스크립트 코드를 읽어들여 실행하는 자바스크립트 엔진(javascript engine)

2. html, css 코드를 가지고 브라우저에 화면을 그려내는 렌더링 엔진(rendering engine)

 

Chrome 과 Node.js 가 구글의 V8 엔진을 사용하고 있다는 것을 많이 들었을 것이다.

※ 참고로 V8 엔진은 C++로 작성되었다.

 

자바스크립트 엔진의 구조

자바스크립트 엔진의 구조

Memory Heap: 동적인 메모리 할당이 일어나는 영역

Call Stack: 함수 호출시 해당 함수가 쌓이는 스택 영역. 함수 요청 순서에 따라 push 및 pop 이 일어난다.

 

익히 알고 있다시피 자바스크립트는 Single-Thread, 싱글 쓰레드 기반 언어이다.

즉, 위에서 언급한 Call Stack(이하 호출스택) 역시 단 하나만 제공한다. 한 번에 하나의 작업만 가능한 구조다.

 

함수를 만나면 해당 함수는 호출스택에 push 되고 (실행 시점에 있는 함수는 호출스택에 최상단에 위치하게 된다.)

함수가 종료되면 pop 되는, 흔히 알고있는 그 스택 구조다.

물론 Call Stack 에는 최대 허용치가 있고, 이를 초과하여 함수가 쌓이게 되면 브라우저가 에러를 발생시킨다.

Uncaught RangeError: Maximum call stack size exceeded

 

여기서 문제가 하나 있는데, 만약 응답이 오래 걸리는 함수가 호출된다면?

한 번에 하나의 작업밖에 실행할 수 없는 자바스크립트 엔진의 위와 같은 구조상

이후 호출될 함수들은 먼저 실행된 함수가 끝날 때 까지 기다릴 수밖에 없다.

심지어 이때 브라우저는 멈춰있는 상태가 된다. (아무것도 처리할 수 없는 상태다)

 

사실 우리는 정답을 알고있다. 그래서 비동기 콜백을 이용하는 것이다.

함수 호출과 동시에 응답을 기다리지 않고 후의 함수들을 호출하는 것이다.

흠 그렇다면 뒤늦게 온 응답은 어떻게 처리된단 말인가.. 호출스택 만으로는 불가능하다. 

 

그.래.서

비동기 처리를 위해, 즉 동시성 제공을 위해 브라우저가 제공하는 몇가지 영역이 더 존재한다.

비동기 함수들의 경우, 브라우저가 제공하는 Web APIs 라는 영역에서 처리된다.

이 녀석은 setTimeout, ajax 요청 등 비동기 처리를 담당한다

 

예를들어보자.

const someMethod = () => setTimeout(() => console.log("First"), 500)
const anotherMethod = () => console.log("Second")

someMethod()
anotherMethod()

 

위의 코드는 다음과 같은 순서로 위 코드가 구동될 것이다.

 

1. someMethod 가 호출스택으로 push 된다.

2. someMethod 내에서 호출된 setTimeout 함수가 다시 호출스택에 push 된다.

3. setTimeout 내의 익명함수는 Web APIs 로 넘어간다.

4. setTimeout 함수는 호출스택에서 pop 되고 

5. someMethod 가 호출스택에서 pop 된다.

 

그리고 이 Web APIs 가 호출스택과 별개로 setTimeout을 처리한다.

500ms 가 지나면 콜백함수를 수행할 것이다.

 

여기서 중요한 점이 등장한다. 콜백 함수는 호출 스택으로 바로 가지 않는다.

위 그림의 Callback Queue로 차례 차례 들어간다.

 

그리고 Event Loop 라는 녀석이 호출스택이 빌 때까지 기다렸다가 호출스택이 비게 되는 시점에

Callback Queue 에서 먼저 들어온 순서대로 다시 해당 함수를 호출스택에 push 하여 실행한다.

위에서 작성하던 순서를 이어서 작성하면

 

6. anotherMethod 가 호출스택으로 push 된다.

7. console.log("Second") 가 실행되고 anotherMethod 가 pop 된다.

8. 특정 시점에 Queue에 들어간 익명함수가 event loop를 통해 호출스택에 push 된다.

9. console.log("First") 가 실행되고 익명함수가 pop 된다.

 

 

추가적으로.. 만약 setTimeout 에 500 이 아닌 0 을 주었다면 결과는 어떻게 될까?

 

사실 결과는 같다. setTimeout을 사용한 순간 Web APIs 가 처리하게 되는거고,

0ms 만에 응답이 왔다고 해도, 호출 스택이 빌 때까지 Queue 에서 기다리게 되므로

실행 순서는 위의 예제와 동일한 결과가 나오게 된다.

 

 

이상으로 event loop 에 대하여 간단히 정리해 보았다.

정말 두서없이 작성한 거 같은데.. 아마 수정을 좀 해야하지 않을까 싶다

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함