Event Loop?
Event Loop란 자바스크립트에 기반인 동시성 모델이라고 합니다. 이벤트 루프는 코드 실행과 collecting(이벤트 수집)
and processing events(이벤트 처리), queued sub-tasks(큐에 놓인 하위 테스크) 실행을 담당합니다.
이 모델은 C언어와 Java와는 확실히 다른 언어에 해당합니다.
JS Engine
자바스크립트 엔진은 Memory Heap(메모리 힙)과 Call Steak(콜 스택)으로 구성되어 있습니다.
자바스크립트는 단일 스레드 프로그래밍(single thread Programming)언어 인데, 이 의미로는 Cell Steak이 하나라는
이야기 입니다.
- Memory Heap: 메모리 할당이 일어나는 곳 (즉 우리가 프로그렘에 선언한 변수, 함수가 담겨저 있다)
- Call Stack: 코드가 실행될 때 쌓이는 곳, stack 형태로 쌓인다.
- Stack(스택): 자료구조 중 하나, 선입후출(LIFO, Last In First Out)의 룰을 따른다.
Web API
위 그림의 오른쪽에 해당하는 Web API는 JS Engine의 밖에 그려저 있다.
즉, 자바스크립트 엔진은 아니다.
Web API는 브라우저에서 제공하는 API로, DOM, Ajax, Timeout 등이 있다.
Call Stack에서 실행된 비동기 함수는 Web API를 호출하고,
Web API는 콜백함수를 Callback Queue(콜백 큐)에 밀어 넣는다.
Callback Queue
비동기적으로 실행된 콜백함수가 보관되는 영역입니다.
예를 들어 setTimeout에서 타이머 완료 후 실행되는 함수(첫번째 값으로 인자)
addEventListner에서 click 이벤트가 발생할때, 실행되는 함수 (두번쨰는 인자) 등이 보관된다.
- Queue(큐) : 자료 구조 중 하나, 선입선출(FIFO, First in First OUT)의 룰을 따른다.
Event Loop
Event Loop는 Call Stack과 Callback Queue의 상태를 체크해
Call Stack이 빈 상태가 되면, Callback Queue의 첫번째 콜백을 Call Stack으로 밀어넣습니다.
이렇게 반복적인 행동을 틱(tick)이라 부릅니다.
이벤트 루프의 동작
이벤트 루프는 어떠한 우선 순위로 작동할까?
그림상으로 설명
- T: task queue
- rAF : request Animation Frame
- S: Style(랜더 트리 생성)
- L: Layout
- P: Paint
중앙을 기준으로 완쪽 path가 task queue, 오른쪽 path가 브라우저 렌더링이라 생각하면 된다.
이 그림에서 보면서 이벤트 루프 과정을 따라가 보자.
1. 초기 콜 스택에 쌓여있는 task를 모두 처리
처음 html을 가져오고 script 태그를 만나는 순간을 생각하면, 브라우저 렌더링 과정에 들어가기 전에
동작을 잠깐 멈추고 자바스크립트 코드를 읽기 시작한다. 자바스크립트 코드가 DOM 트리를 수정할
수 있기 때문이다. 이 과정에서 코드들이 콜 스택에 올라가 동작을 수행하고 Promise나
setTimeout과 같은 비동기 관련 콜백들이 queue에 등록된다.
2. Promise.then 콜백이 microtask queue에 등록되어 있다면 실행
처음 콜 스택에 있는 코드들이 모두 실행되고 난 후 Promise가 가장 높은 우선순위를 차지한다.
Promise.then 콜백이 등록된 microtask queue는 특징이 하나 있는데, queue에 등록된 모든
콜백이 처리될 때까지 계속 수행한다는 것이다.
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
이 코드는 어떤 순서로 실행될까?
script start
script end
promise1
promise2
setTimeout
script start, script end 순으로 처리되는건 알겠는데,
왜 Promise, setTimeout 순으로 실행되는 것일까?
여기서 Microtask Queque의 개념이 나온다.
Event Loop는 우선적으로 Microtask Queue를 확인한다.
만약 Microtask Queue에 콜백이 있다면, 이를 먼저 Call Stack에 담는다.
그리고 Microtask Queue에 더이상 처리해야할 콜백이 없다면,
Task Queue에 확인 후 처리한다.
Promise의 then()의 콜백은 Task Queue가 아닌 Microtask Queue에 담긴다.
따라서 위 코드에서는 우선순위가 높은 Microtask Queue부터 처리되므로,
Promise의 then() 콜백이 다 실행되고, setTimeout 콜백이 실행되는 것이다.
Animation Frames???
Animation Frames라는 개념도 있다.
requestAnimationFrame API가 실행되면 콜백이 Animation Frames로 담긴다.(setTimeout이 실행되면 타이머 완료후
콜백이 Task Queue에 담긴 것 처럼..)
그럼 Microtask Queue, Task Queue, Animation Frames의 우선순위를 살펴보자.
console.log("script start");
setTimeout(function() {
console.log("setTimeout");
}, 0);
Promise.resolve().then(function() {
console.log("promise1");
}).then(function() {
console.log("promise2");
});
requestAnimationFrame(function() {
console.log("requestAnimationFrame");
})
console.log("script end");
콘솔 창에서 위 코드를 실행시키면,
script start
script end
promise1
promise2
requestAnimationFrame
setTimeout
- Microtask Queue > Animation Frames > Task Queue 순으로 실행된다. (크롬 기준)
정리
- V8 엔진에서 코드가 실행되면, Call Stack에 쌓인다.
- Stack의 선입후출의 룰에 따라서 제일 마지멕에 들어온 함수가 먼저 실행되며,
Stack에 쌓인 함수가 모두 실행된다.- 비동기 함수가 실행되면, Web API가 호출된다.
- Web API는 비동기 함수의 콜백함수를 Callback Queue에 밀어넣는다.
- Event Loop는 Call Stack이 빈 상태가 될때 Callback Queue에 있는 첫번째 콜백을
Call Stack으로 이동시킨다. (이러한 반복적인 행돌을 tick(택)이라 한다.
실제로 실행시, setTimeout과 requestAnimationFrame의 순서가 바뀌는 결과도 있었다.
우선순위는 분명 Animation Frames가 Task Queue보다 높다고 했는데..
브라우저는 좋은 사용자 경험을 위해 초당 60번 화면을 렌더링 한다고 한다.
이를 위해서는 16ms안에 1번 화면을 그려주어야 한다.
만약 Microtask Queue안에 있던 콜백은 다 Call Stack으로 이동되었고,
Animation Frames과 TaskQueue에 모두 콜백이 잇다고 거정하고,
만약 Task Queue의 콜백이 먼저 Cell Stack으로 이동되어도
16ms안에 1번 렌더링 할 수 있다면, Task Queue의 콜백이 먼전 이동되는 것이 아닐까?
Microtask Queue의 콜백을 많이 만들어
일정 시간동안 Animation Frame과 Task quque의 콜백이 그대로 쌓여있을 경우
Microtask Queue의 콜백이 모두 Cell Stack으로 이동되었을 때 (즉 MicroTask Queue가 빈상태일 경우)
Animation Frames 에 쌓여있던 Callbak이 모두 다 Stack으로 이동되어야
Task Queue에 쌓여있던 콜백이 이동한다.
즉, Animation Frames가 Task Queue보다 우선순위가 높게 작용했다.
Event Queue ?? Job Queue??
마지막으로 Event Queue, Job Queue라는 개념도 나온다.
Event Queue는 Task Queue의 동일한 역할을,
Job Queue는 Microtask Queue의 동일한 역할을 가지고 있다.
Render Queue??
- Render Queue는 브라우저에서 사용자에게 래스터 이미지를 보여주기 위해 HTML, CSS,Javascript 코드를 변환하는 과정을 의미한다. (rendering path 혹은, cirtical rendering path 라고도 한다.)
- DOM Tree -> CSS Tree -> CSSOM -> Render Tree -> Layouting -> Layout Tree -> Paint -> GPU Syne ->
Composition 순으로 이루어 지는데, Composition은 스크린에 그려진 Final Frame이다.
참고
'프론트 엔드 > Javascript' 카테고리의 다른 글
[Javascript] 자바스크립트 엔진, V8 (0) | 2022.01.30 |
---|---|
[Javascript] OOP vs FP란 무엇인가? (0) | 2022.01.23 |
[Javascript] null과 undefined의 차이 (0) | 2022.01.23 |