일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 송고버섯피자
- 마연굴
- 한국걱정
- neovim
- 이코노미스트한국구독센터
- 프로젝트헤일메리
- deepseek
- 런데이애플워치
- lner
- 마법의연금굴리기
- 달리기
- kafka-connect
- 강릉여행
- 잘쉬어야지
- 루스틱
- 저동하녹
- 여행
- apollo-sandbox
- 일권하는사회
- 플라스틱은 어떻게 브랜드의 무기가 되는가
- 가람집옹심이
- apollo-server-v3
- 여니브레드
- 트럼프2.0시대
- schema-registry
- 오운완
- 런데이
- 중사랑
- Zone2
- 티지아이포럼
- Today
- Total
해뜨기전에자자
Eventloop: macrotask and microtask 본문
ECMAScript에는 이벤트 루프가 없다.
Nodejs 뿐만 아니라 브라우저 javascript 실행 흐름은 Eventloop를 기반으로 한다.
Eventloop의 작동 방식을 이해하는 것은 최적화 및 올바른 아키텍처에 중요하다. 그러나 event loop의 개념은 HTML 스펙에 정의되어있다. https://html.spec.whatwg.org/multipage/webappapis.html#event-loops
Nodejs와 브라우저에서의 javascript, eventloop 의 관계
eventloop는 javascript의 스펙이 아니다. javascript는 Heap, stack만 존재하고 실제로 eventloop는 javascript 실행환경에 있다. 왼쪽은 브라우저 환경에서의 이벤트루프이고, 오른쪽 그림은 nodejs 환경에서의 eventloop이다. javascript와 이벤트루프가 분리되어있다는 것은 아래와 같은 도식으로도 확인할 수 있다. 브라우저를 기준으로 설명해보면 webAPIs, 로딩, setTimeout의 콜백들은 eventloop가 실행시킨다.
단일 호출 스택과 Run-to-Completion
- Javascript는 단일 호출 스택을 가지고 있고, 하나의 자바스크립트 코드(Task)가 모두 실행될때까지 다음 작업은 실행되지 않는다.
- Javascript는 script/handler/event activates 을 실행시키는 것 외에 대부분의 시간 동안 아무것도 하지 않는다.
- 실행 단위들은 task라고 부른다. task들은 macrotask queue (v8 term)에 들어간다.
Macrotask - Task Queue
<script src="...">
가 로딩 되었을 때 실행시키는 것- 유저가 마우스를 움직였을때, mousemove 이벤트를 dispatch 하고, handler를 실행시키는 것
- setTimeout에 스케줄 된 시간이 다 되었을 때, callback을 실행시키는 것
- .. etc
개발 시에는 두가지 고려해야 할 점이 있다.
- 엔진이 task를 실행시키는 동안 rendering 이 일어나지 않는다. task가 오래 실행 되는지 상관하지 않고, task가 완료된 후에 DOM의 변경 사항이 painted된다.
- task가 시간이 너무 오래 걸릴 경우, browser 가 다른 task를 실행하거나 user event를 처리하지 못하고 얼마간 시간이 지나 "페이지가 응답하지 않습니다" 같은 알람을 받게 될 수 있다.
EventLoop
- A fundamental abstract concept of the JavaScript programming model
- 이벤트루프의 구현은 아래와 같이 표현될 수 있다. microTask가 도입되기 전 기본적인 컨셉은 아래와 같다.
while (true) {
const task = eventLoop.nextTask();
if (task) {
task.execute();
}
if (eventLoop.needsRendering())
eventLoop.render();
}
Microtask - Job Queue
ES6/ ES2015 부터 도입된 Promise는 Microtask로 JobQueue에 들어간다. 한 루프에서 하나의 microTask를 실행하지만, macroTask는 해당 큐가 비어질때까지 계속 실행된다. 이 과정에 끝나야 DOM의 변경사항이 painted가 되기 때문에 promise에서 cpu를 과도하게 점유시키고 끝나지 않는 경우 브라우저가 멈추는 현상이 일어날 수 있으므로 주의해야한다. 아래 슈도 코드를 보자.
Eventloop pseudo code
while (true) {
const task = eventLoop.nextTask();
if (task) {
task.execute();
}
for(let microTask of queueMicrotask)
microTask.execute();
if (eventLoop.needsRendering())
eventLoop.render();
}
Practice
결과를 예상해보자
while (true) {
const task = eventLoop.nextTask();
if (task) {
task.execute();
}
for(let microTask of queueMicrotask)
microTask.execute();
if (eventLoop.needsRendering())
eventLoop.render();
}
- 결과
script start script end promise1 promise2 setTimeout1
- 퀴즈: 왜 promise1이 setTimeout1보다 먼저 나올까?
- 이유는 script start, script end 의 스크립트 부분이 global task 에 속해 MacroTask가 되기 때문이다. 틀린 사람은 "단일 호출 스택과 Run-to-Completion"의 Task 종류(=macrotask)에 대해 다시 살펴보자.
- 단순히 microTask, macroTask의 개념에서 봤을때 브라우저 등 실행환경에 따라 이 순서는 바뀌지 않는다. 그러나 다른 이벤트 (ex scroll, resize, rAF 등)의 경우 실행 환경에 따라 순서의 차이가 있을 수 있다. 자세한 실험 결과는 A dive into event loop specification 에서 확인할 수 있다.
Ref
- https://javascript.info/event-loop
- https://meetup.toast.com/posts/89
- https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
- Event loop explainer
https://github.com/atotic/event-loop#event-loop-description - A dive into event loop specification
https://cdn.rawgit.com/atotic/event-loop/caa3cfd4/rendering-events.html - Nodejs의 Eventloop를 Phase별로 설명한 글
https://evan-moon.github.io/2019/08/01/nodejs-event-loop-workflow/