Javascript] 이벤트 루프

Song-Minhyung·2022년 6월 9일

Javascript

목록 보기
5/8
post-thumbnail

블로킹(blocking)

자바스크립트는 싱글스레드로 이벤트 루프가 한개만 돌아간다 (이벤트 루프가 무엇인지는 아래에서 설명!)
그래서 for문이 1억개 돌아가는 등의 무거운 작업이 중간에 있다면 블로킹 현상에 걸린다.
즉, 프로그램이 무거운 작업을 처리하는 시간동안 멈추게 돼버린다.

button.addEventListener("click",() => {
    for(let i = 0; i < 100000000; i++){}
    alert("클릭!");
});

위의 코드는 for문이 전부 돌아갈때까지 화면에서 아무런 클릭도 할 수 없고
for문이 전부 돌아야 alert가 실행된다.

블로킹(blocking) 해결방법

그럼 위의 블로킹 현상은 어떻게 해결할까?
답은 간단하다 무거운 작업을 비동기적으로 처리해주면 된다!

비동기 처리

비동기 처리는 무거운 작업이 완료될 때 까지 기다리지 않고 다음 작업을 먼저 처리한다.
그리고서 무거운 작업이 완료되면 그 떄 값을 받아온다.
하지만 비동기 처리는 실행 순서가 보장되지 않으므로 신경써서 처리해야한다.

보통 비동기 처리는 콜백함수를 넘겨주는 방식을 사용한다.

function getSomeThing (){
    console.log('I got it!');
}

function doSomeThing () {
    console.log('doing');
}

setTimeout(getSomeThing, 1000);
doSomeThing();

위 코드는 setTimeout을 사용해 서버와 통신하는 과정을 가정한것이다.
서버와 통신에 성공하면 getSomeThing 함수를 실행한다.
이렇게 하면 처리순서가 보장이 된다.

비동기의 작동원리

또 다른 하나의 코드를 보겠다.

console.log("1");
setTimeout(() => {
  console.log("2");
}, 0);
console.log("3");

위의 코드는 어떻게 출력될까? 정답은 1 3 2 이다.
분명히 setTimeout이 0초후에 실행되니 바로 실행될거라 생각했는데
이렇게 출력되는지 이해하려면 글의 주제인 이벤트 루프를 이해해야한다.

그래서 이벤트 루프가 뭔데?

여러가지 일의 처리를 한번에 가능하게 하는것, 그게 자바스크립트의 이벤트 루프이다.
위의 코드들을 다시 한번 살펴보면 다른 함수가 먼저 실행된 후에
setTimeout에 콜백함수로 넘긴 함수가 나중에 실행됐다.

만약 비동기로 코드가 작동하지 않았다면 아래처럼 동작했을것이다.

  1. 1초를 기다린다.
  2. getSomeThing 함수를 실행한다.
  3. doSomeThing 함수를 실행한다.

하지만 비동기로 코드가 작동했기 때문에 딜레이가 없어보인다.
이렇게 이벤트 루프는 자바스크립트가 동시성을 가질 수 있게 해준다.

이벤트 루프는 다음과 같이 작동한다.

  1. 자바스크립트 엔진이 코드를 평가, 실행한다.
  2. 호스팅 환경(node.js, 브라우저 등)이 이를 등록한다.
  3. 이벤트 루프가 등록된 함수를 스케줄링 한다.

그렇다.
이벤트 루프실행 순서를 스케줄링 하는 역할을 한다.
더 자세히 이해하려면 자바스크립트엔진과 호스팅 환경의 이해가 필요하다.

자바스크립트 엔진과 호스팅 환경

자바스크립트 엔진의 구조는 너어무 심플하다. 콜스택 그리고 힙메모리가 존재한다.

콜스택:

  • 엔진이 함수등을 평가할 떄 생성되는 실행 컨텍스트가 스택형식으로 쌓인다.
  • 자바스크립트가 동기적인 이유는 스택에 쌓인 순서대로 코드가 작동하기 때문이다.

힙메모리:

  • 자바스크립트의 참조객체가 저장되는 장소이다.

다음은 호스팅 환경이다. (브라우저 혹은 node.js)

Task Queue(Macrotask Queue):

  • setTimeOut, setInterval, setImmediate 과 같은 task를 넘겨받는다.
  • Macrotask Queue에 있는 함수들은 비동기 처리 방식으로 동작한다.

Microtask Queue:

  • Promise, async/await, process.nextTick, Object.observe, MutationObserver
    과 같은 비동기 호출을 넘거받는다.
  • 우선순위가 Macrotask Queue보다 먼저이다.

request Animation Frame:

  • 렌더링과 관련된 task를 넘겨받는 Queue다.
  • 우선순위는 호스팅 환경마다 다르다.
  • 이번 글에서 raf에 대해서는 설명하지 않을거다.

그림으로 나타낸다면 아래와 같을것이다.

이벤트 루프의 작동순서

이벤트 루프는 말 그대로 loop다. 빙글빙글 돌아간다!

  1. 이벤트 루프를 순회하면서 콜스택이 깨끗한지 체크한다. Tick이라 표현하다.
  2. 틱이 한번 발생할 Microtask Queue에 task가 있는지 확인하고 있다면 하나씩 전부 꺼내 콜스택으로 넘겨준다.
  3. Macrotask Queue에 task가 있는지 확인한다. 있다면 하나씩 꺼내 콜스택으로 넘겨준다.
    이때 Microtask Queue와는 다르게 큐가 한번에 비워지지 않고 중간에 콜스택이 쌓인다면
    비워질 때 까지 대기한다.
  4. 1부터 3까지 계속 반복한다.

마치며

이벤트 루프 다음에는 promis와 async / await이 어떻게 작동하는지 정리 할 것이다.
커뮤니티 사이트를 보다가 재밌는 예제를 발견했는데 해당 예제의 설명과 함께 글을 쓸 예정이다.
이번 주제의 정리를 적으며 글을 마친다.

  • 이벤트 루프는 호스팅 환경에서 등록된 task의 스케줄링을 하는 역할을 한다.
  • MicrotaskQueue, MacrotaskQueue, rAF에 task를 등록하는데 우선순위는 MicrotaskQueue가 높다.
  • MicrotaskQueue는 큐의 내용을 한번에 pop하지만 MacrotaskQueue는 그렇지 않다.
  • 이벤트 루프가 Blocking 된다면

아래 두개의 유튜브는 꼭 봐야한다. 그러면 이해도가 한층 더 높아진다.
https://www.youtube.com/watch?v=8aGhZQkoFbQ
https://www.youtube.com/watch?v=cCOL7MC4Pl0

참고

profile
기록하는 블로그

0개의 댓글