이벤트루프

김예찬·2021년 6월 2일
0

javascript의 중요한 개념인 이벤트루프를 정리합니다😁

본 포스팅은 ko.javascript.infonhn cloud를 토대로 작성되었습니다.

자바스크립트의 특징

자바스크립트는'단일 스레드' 기반의 언어이다. 동시에 단 하나의 작업만을 처리할 수 있다. 하지만, 사용자들에겐 많은 작업들이 동시에 처리되고 있다고 생각한다. 마우스의 입력을 받으면서 애니메이션 효과를 보여주고, HTTP 통신을 통해 서버에서 JSON 정보를 가져 오는 등, 어떻게 동시성(Concurrency)를 지원하는 지의 정답은 이벤트 루프에 있습니다.

브라우저

프론트엔드에겐 브라우저의 환경이 가장 중요함. 브라우저 또한 Node.js와 마찬가지로 이벤트 루프에 기반 함으로, 이벤트 루프가 어떻게 동작하는 지 잘 이해하고 있어야 올바른 사용이 가능합니다.

이벤트 루프

이벤트 루프는 태스크(해야할 일, 사용자가 일으킨 이벤트 등이라고 볼 수 있겠습니다)가 들어오면 이를 처리하고, 없으면 쉬는 일꾼이 일하는 루프입니다.

자바스크립트 엔진을 활성화하는 태스크는 대표적으로

  • 외부 스크립트 <script src="...">가 로드될 때,
  • 사용자가 마우스를 움직이거나 클릭하는 등의 이벤트가 일어날 때,
  • setTimeout 등의 콜백 함수를 실행 할 때

등이 있습니다.

매크로태스크 큐

자바스크립트 엔진이 많은 태스크로 바쁘면 밀린 일(태스크)들은 macrotask queue에 들어 가는데, 이름에서도 알 수 있듯이 먼저 들어간 친구가 먼저 나오는 큐 자료구조 입니다.
예를 들어 엔진이 엄~청 긴 script를 처리하고 있는 상황에 브라우저 사용자가 마우스를 움직이는 이벤트를 발생 시키면, 마우스를 통해 발생된 이벤트는 큐에 들어가 script 처리를 기다린 후, 콜 스텍으로 옮겨집니다.

CPU 소모가 많은 태스크 쪼개기

위에서 들은 예시 처럼 엄~청 긴 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>

이벤트 루프를 잘 보여주는 시각자료

profile
프론트엔드

0개의 댓글