Event loop

📅 TIL #132




🎯 Achievement Goals

  1. Event loop의 작동 원리에 대해서 이해한다.







Event loop


자바스크립트_이벤트루프


정말 꼭 배워보고 싶었던 Event loop!! 좋은 동영상도 보고, 자료도 많이 읽어봤지만 이렇게 블로깅을 하는 것은 처음이다. 내가 어떻게 생각하고 있는지 한 번 정리해보려고 한다.


위의 사진은 자바스크립트 엔진의 구조이다. (그 중에서도 V8엔진이다.) 그럼 각각 무슨 역할을 하는지 알아보자.


Memory Heap은 메모리 할당이 일어나는 곳이다.

Call Stack은 실행 될 코드를 한 줄 단위로 할당 한다.

Web APIs는 비동기 처리를 담당한다.

Callback Queue(안에 Task Queue, Event Queue등이 있음)는 비동기 처리가 끝난 후 실행해야 할 콜백 함수를 차례대로 할당한다.

Event Loop는 Queue에 할당된 함수를 순서에 맞춰 Call Stack에 할당해준다.


그럼 이제 각자의 역할을 알았으니 작동 원리를 살펴 보자.


console.log("시작");

setTimeout(() => {
  console.log("중간");
}, 1000);

console.log("");


위의 코드는 어떤 순서로 실행이 될까?


evetloop1


먼저 호출 스택(콜 스택)에는 항상 코드들을 가지고 있는 anonymous(main)가 들어간다. 이후에 첫번째로 찍히는 콘솔 ‘시작’이 찍힌다.



evetloop2


호출 스택이기 때문에 ‘시작’은 바로 호출이 되고, 그 다음 콘솔 ‘중간’이 온다. 하지만 비동기 함수이기 때문에 호출하지 않고 Web APIs로 넘어간다.
(setTimeout의 두번째 인자가 1000이 아니라 0이여도 넘어간다.)



evetloop3


여기서가 중요하다! 콜백 큐(테스크 큐)에 있는 익명 함수는 항상 대기하고 있다가 호출 스택이 비워지면(전역 컨텍스트 anonymous(main)의 실행이 종료되면) 그 때 함수를 하나씩 호출 스택으로 밀어 올린다.



evetloop4


그리고 마지막으로 콘솔 ‘중간’을 호출하면서 순서는 시작-끝-중간 순으로 출력한다.




그 다음 코드는 어떤 순으로 출력할까?


console.log("시작");

setTimeout(() => {
  console.log("중간");
}, 0);

Promise.resolve().then(() => {
  console.log("프로미스");
});

console.log("");



callstack5


프로미스와 setTimeout의 순서는 현재 코드로는 판단할 수 없지만 setTimeout 먼저 실행된다고 가정한다. 그리고 setTimeout-프로미스 순으로 콜백 큐에 함수가 쌓일 예정이다.



callstack6


그러면 호출 스택의 콘솔들이 다 호출 된 이후에는 예상대로 setTimeout이 호출 스택에 올라가고 프로미스가 그 다음으로 올라갈 것이라고 생각했다. 하지만 콜백 큐(테스크 큐)에는 우선순위가 존재했다..!!





callback7


사실 내가 알고 있는 콜백 큐안에는 3가지로 이루어져 있었다. 이 3가지에서 우선 순위가 있고 이 우선 순위대로 호출 스택에 쌓인다.


가장 먼저 프로미스는 Microtask Queue에 속한다. 그리고 setTimeout은 Task Queue에 쌓인다. 그렇기 때문에 콜백 큐에 setTimeout이 먼저 쌓여 있어도, 결국엔 프로미스먼저 호출을 한다는 뜻이다.


그래서 호출 순서는 시작-끝-프로미스-중간 순으로 출력한다.





참고 자료

호출 스택과 이벤트루프