javascript의 중요한 개념인 이벤트루프를 정리합니다😁
본 포스팅은 ko.javascript.info와 nhn cloud를 토대로 작성되었습니다.
자바스크립트는'단일 스레드' 기반의 언어이다. 동시에 단 하나의 작업만을 처리할 수 있다. 하지만, 사용자들에겐 많은 작업들이 동시에 처리되고 있다고 생각한다. 마우스의 입력을 받으면서 애니메이션 효과를 보여주고, HTTP 통신을 통해 서버에서 JSON 정보를 가져 오는 등, 어떻게 동시성(Concurrency)를 지원하는 지의 정답은 이벤트 루프
에 있습니다.
프론트엔드에겐 브라우저의 환경이 가장 중요함. 브라우저 또한 Node.js
와 마찬가지로 이벤트 루프에 기반 함으로, 이벤트 루프가 어떻게 동작하는 지 잘 이해하고 있어야 올바른 사용이 가능합니다.
이벤트 루프는 태스크(해야할 일, 사용자가 일으킨 이벤트 등이라고 볼 수 있겠습니다)가 들어오면 이를 처리하고, 없으면 쉬는 일꾼이 일하는 루프입니다.
자바스크립트 엔진을 활성화하는 태스크는 대표적으로
<script src="...">
가 로드될 때,이벤트
가 일어날 때,setTimeout
등의 콜백 함수를 실행 할 때등이 있습니다.
자바스크립트 엔진이 많은 태스크로 바쁘면 밀린 일(태스크)
들은 macrotask queue
에 들어 가는데, 이름에서도 알 수 있듯이 먼저 들어간 친구가 먼저 나오는 큐 자료구조
입니다.
예를 들어 엔진이 엄~청 긴 script를 처리하고 있는 상황에 브라우저 사용자가 마우스를 움직이는 이벤트를 발생 시키면, 마우스를 통해 발생된 이벤트는 큐에 들어가 script 처리를 기다린 후, 콜 스텍
으로 옮겨집니다.
위에서 들은 예시 처럼 엄~청 긴 script나 처리해야 될 데이터가 많은 일은 많은 cpu를 소모하게 되므로, 브라우저
멈춤 현상이 나타나는 원인이 됩니다.
다음 매크로태스크 큐가 늦게 일어나는 코드
let i = 0;
let start = Date.now();
function count() {
// CPU 소모가 많은 무거운 작업을 수행
for (let j = 0; j < 1e9; j++) {
i++;
}
alert("처리에 걸린 시간: " + (Date.now() - start) + "ms");
}
count();
setTimeout 호출을 이용해 태스크를 쪼개서 문제 해결
let i = 0;
let start = Date.now();
function count() {
// 무거운 작업을 쪼갠 후 이를 수행 (*)
do {
i++;
} while (i % 1e6 != 0);
if (i == 1e9) {
alert("처리에 걸린 시간: " + (Date.now() - start) + "ms");
} else {
setTimeout(count); // 새로운 호출을 스케줄링 (**)
}
}
count();
프로그래스 바를 이용해 태스크를 여러 개로 쪼갤 때의 장점을 더 알아봅시다.
태스크를 쪼개지 않아 변화가 보여지지 않고 결과만 보여지는 코드
<div id="progress"></div>
<script>
function count() {
for (let i = 0; i < 1e6; i++) {
i++;
progress.innerHTML = i;
}
}
count();
</script>
태스크를 쪼개 중간 중간 결과가 화면에 나타나는 코드
<div id="progress"></div>
<script>
let i = 0;
function count() {
// 무거운 작업을 쪼갠 후 이를 수행
do {
i++;
progress.innerHTML = i;
} while (i % 1e3 != 0);
if (i < 1e7) {
setTimeout(count);
}
}
count();
</script>