console.log와 web api를 쓰면서 console.log가 왜 먼저 동작하는지 궁금했지만 정작 찾진않았다.(과거의 나 반성해라..) 그런데 멘토님이 멘토링 시간에 이벤트 루프가 뭔지 공부해보라 하셔서 그 계기로 글을 쓰게되었다 ㅎㅎ 소스 제공 감사합니당 😊
자바스크립트는 싱글 스레드로 동작한다. 하지만 브라우저가 동작하는 것을 살펴보면 많은 태스크가 동시에 처리되는 것처럼 느껴진다. 예를 들어, HTML 요소가 애니메이션 효과를 통해 움직이면서 이벤트를 처리하고, HTTP 요청을 통해 서버로부터 데이터를 가지고 오면서 렌더링하기도 한다. 이처럼 자바스크립트의 동시성을 지원하는 것이 바로 이벤트 루프이다.
싱글 스레드 → 한 번에 하나의 일만 수행할 수 있는것을 의미
스레드 → 프로세스의 실행 단위
싱글 스레드에 대해서도 해야할 말이 많지만 간단히 개념만 설명하고! 추후에 블로그에 써보겠당 😎
갑자기 브라우저 환경에 대한 얘기가 왜 나오냐고 묻는다면 아래와 같이 설명하려한다. JS는 비동기 작업이 가능하려면 JS 엔진을 구동하는 환경(브라우저나 Node.js)가 필요하다. 그렇기에 브라우저 환경을 알아야하는데 어떻게 되어있는지 아래 그림으로 확인하자.
그림 출처 - https://poiemaweb.com/js-event
❗ 해당 그림에는 마이크로 태스크 큐, 매크로 태스크 큐, 애니메이션 프레임가 없는데 이 세 가지는 이벤트 큐(=태스크 큐 or 콜백 큐)에 들어가있다.
그림에서 보이듯 역할이 여러가지로 나뉘어져 있는것이 보이는데, 다음은 각자 하는 역할을 정리한 것이다.
❗ JS의 엔진은 Call stack과 Heap이고, 밑의 나머지 설명들은 웹 브라우저의 구조에 대한 설명이다.
Web API
Callback Queue(= Event Queue)
- 비동기 작업이 완료되면 실행될 함수들이 대기하는 공간
- 타이머, 네트워크 요청, 사용자 인터페이스 이벤트 등이 완료되면 해당 콜백이 이벤트 큐에 들어감
- 브라우저 런타임이나 Node.js 런타임이 담당함
콜백 큐에는 마이크로 태스크 큐와 매크로 태스크 큐와 애니메이션 프레임이 별도로 존재함.
마이크로 태스크 큐 → 애니메이션 프레임 → 매크로 태스크 큐순으로 실행된다. (마이크로 태스크 큐가 비어있으면 애니메이션 프레임이 실행되고, 애니메이션 프레임이 비어있으면 매크로 태스크 큐가 실행됨)
💡 fetch나, axios같은 네트워크 요청(=매크로 태스크 큐)은 마이크로 태스크 큐에 직접 포함되진 않지만 .then() 콜백은 마이크로 태스크 큐에 포함된다.
매크로 태스크 큐(Macro Task Queue)
애니메이션 프레임(Animation Frames)
- 'requestAnimationFrame'을 통해 등록된 콜백들을 의미(웹 브라우저에서 애니메이션을 부드럽게 실행하기 위한 메커니즘)
Event Loop
Event Table
브라우저 환경을 알았다면 이벤트 루프가 무슨 역할을 하는지 알아보자. 이벤트 루프의 주요 역할은 JS가 비동기적으로 작업을 처리할 수 있게 하는 것이다. 그래서 JS는 싱글 스레드 기반의 언어이며 논 블록킹에 동시성을 지원한다고 한다. 아래의 내용은 이벤트 루프가 하는 역할에 대해 간단히 설명한 내용이다.
학습한 내용을 바탕으로 코드를 구성했다. 아래의 코드 순서가 있을 때 어떤 순서대로 작업이 완료되는지, 그 이유가 무엇인지 설명할 수 있다면 대략적으로 이벤트 루프에 대해 알게된 것이다.
const API_URL = "https://jsonplaceholder.typicode.com/todos/1";
console.log("Hello");
setTimeout(() => {
console.log("setTimeout은 매크로 태스크 큐!!");
}, 1000);
console.log("Hi");
const promise = fetch(API_URL)
.then((res) => {
if (!res.ok) {
throw new Error("promise error");
}
return res.json();
})
.then((data) => console.log("promise Data:", data))
.catch((err) => console.log("err:", err));
console.log("Jetom");
정답은 아래와 같다!
1. "Hello" 출력: 동기적으로 실행되어 즉시 출력
2. "Hi" 출력: 동기적으로 실행되어 즉시 출력
3. "Jetom" 출력: 동기적으로 실행되어 즉시 출력
4. 'setTimeout': 매크로 태스크 큐에 추가
5. 'fetch': 요청이 시작되고, 프로미스의 'then' 콜백이 마이크로 태스크 큐에 추가
6. 콜 스택이 비어 있으면 이벤트 루프는 마이크로 태스크 큐의 작업을 처리
7. "promise Data": "promise Data:", data 출력
8. 마이크로 태스크 큐가 비어 있으면, 이벤트 루프는 매크로 태스크 큐의 작업을 처리
9. "setTimeout": "setTimeout은 매크로 태스크 큐!!" 출력
따라서 Hello 👉 Hi 👉 Jetom 👉 fetch 👉setTimeout 순으로 콘솔이 출력된다!
👇 해당 유튜브 영상은 매크로 태스크 큐(=태스크 큐) 마이크로 태스크 큐(=잡 큐)에 대해서도 같이 나오는 쇼츠이다. 영상 속 나오는 코드가 작아서 보는데 불편하지만 어느정도 이해하는데 도움은 줄수있다.
https://youtube.com/shorts/m8biTN2fBEs?si=JvocvZmCoxaIqiyO
출처 -
모던 자바스크립트 Deep Dive
https://poiemaweb.com/js-event
ChatGPT