JavaScript Visualized: ✨♻️ Event Loop

Posted on August 31, 2020  -  3 min read

reference: https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif

이벤트 루프는 JavaScript 개발자들이 어떤 방법으로든 반드시 다뤄야하는 것들 중 하나입니다. 하지만, 처음엔 이해하기에 좀 헷갈릴 수 있습니다. 전 시각적으로 익히는 사람이기에 여러분들에게 저해상도 gif를 통해 시각적인 방법으로 설명하여 여러분들을 돕고자 합니다. 굳이 저해상도 gif를 사용하는 이유는 지금이 2019년 이지만 여전히 gif들은 픽셀화 되어있고 흐릿하기 때문이죠.

우선, 이벤트 루프가 어떤 것이고, 왜 그걸 여러분들이 신경써야 할까요?

JavaScript는 단일 스레드입니다: 한 번에 하나의 작업만 실행할 수 있죠. 보통 이게 큰 문제가 되지 않지만, 여러분들이 30초가 걸리는 작업을 실행한다고 상상해 보시면..와..30초 동안 우린 아무것도 할 수 없을 거예요. (JavaScript는 기본적으로 브라우저의 메인 스레드에서 실행됩니다. 그리고 UI 전체가 멈출 거예요.) 😬 지금은 2019년이고, 누구도 느리고, 반응성이 떨어지는 웹사이트를 원하지 않습니다.

다행히도, 브라우저는 JavaScript 엔진 자체에서 지원하는 건 아니지만 몇 가지 기능을 제공합니다: Web API죠. 이것은 DOM API, setTimeout, HTTP requests 등을 포함합니다. 이것들은 우리가 비동기나, 넌블럭 동작을 구현하는 데 도움을 줍니다. 🚀

우리가 함수를 호출할 때, 그 함수는 어딘가로 추가가 되는데 그걸 콜 스택이라고 부릅니다. 콜 스택은 JavaScript 엔진의 일부분으로, 브라우저마다 다릅니다. 이것은 스택으로, 선입후출 구조를 가집니다 (팬케이크 더미를 생각해주세요). 함수에서 값을 반환 할 때, 스택에서 Pop이 됩니다. 👋

1 || 함수는 호출 될 때 콜 스택에 Push 되고, 값을 반환할 때 Pop이 됩니다.

respond함수는 setTimeout함수를 반환합니다. setTimeout함수는 Web API에서 제공하는 함수입니다: 이것은 메인 스레드의 블럭 없이 작업을 미루도록 해줍니다. 콜백 함수는 setTimeout함수에 전달했던 함수이며, 화살표 함수인 ()=> { return 'Hey'}가 Web API에 추가되며 그동안, setTimeout함수와 respond함수는 콜 스택에서 Pop이 됩니다. 둘 다 그것들의 값을 반환했죠.

2 || setTimeout은 브라우저가 제공하는 Web API로 우리가 전달한 콜백을 처리해줍니다.

Web API에서, 타이머는 우리가 전달한 인수에 해당하는 시간인 1000ms만큼 동작합니다. 콜백은 그 즉시 콜 스택에 추가되지 않고 그 대신, 큐라고 불리우는 곳에 전달이 됩니다.

3. 타이머가 끝나먼 (이번엔 1000ms입니다) 콜백은 콜백 큐로 전달됩니다.

이 부분이 헷갈릴 수 있는 곳입니다: 1000ms 뒤에 콜백 함수가 콜 스택에 추가된다(따라서 값을 반환함)는 것을 의미하지 않습니다. 간단하게 말하면, 1000ms 뒤엔 큐에 추가가 됩니다. 하지만 이건 대기열로, 함수는 자신의 차례를 기다려야 합니다.

이제 우리 모두가 기다려 왔던 부분입니다. 이벤트 루프가 동작할 유일한 순간입니다: 큐를 콜 스택에 연결하는 것이죠! 만약 콜스택이 비어있다면, 그래서 이전에 호출된 모둔 함수가 값을 반환하고 스택에서 Pop이 되어있다면, 큐의 첫 번째 아이템이 콜 스택에 추가됩니다. 이번 경우엔 호출된 다른 함수가 없습니다. 즉, 콜백 함수가 큐의 첫 번째 아이템이 될 때까지 콜 스택이 비어있었습니다.

4 || 이벤트 루프는 콜백 큐와 콜 스택을 봅니다. 콜 스택이 비버있다면, 큐의 첫 번째 아이템을 스택에 Push합니다.

콜백은 콜 스택에 추가되고, 호출됩니다. 그리고 값을 반환하고, 스택에서 Pop됩니다.

5 || 콜백은 콜 스택에 추가되고 실행됩니다. 값을 반환하면, 콜 스택에서 Pop이 됩니다.


아티클을 읽는 것은 재미있지만 실제로 계속해서 이 기사를 읽음으로써 이 문제에 완전히 익숙해질 것 입니다. 다음을 실행하는 경우 콘솔에 어떤 기록이 남을지 확인해보세요.

const foo = () => console.log('First');
const bar = () => setTimeout(() => console.log('Second'), 500);
const baz = () => console.log('Third');

bar();
foo();
baz();

이해 됐나요? 브라우저에서 이 코드를 실행하면 어떻게 되는지 빠르게 살펴보겠습니다.

  1. bar를 호출합니다. barsetTimeout함수를 반환합니다.
  2. setTimeout에 전달된 콜백은 Web API에 추가됩니다. setTimeout함수와 bar가 콜 스택에서 Pop됩니다.
  3. 타이머가 동작하는 동안 foo가 호출되고 First를 남깁니다. fooundefined를 반환합니다. baz가 호출되고, 콜백은 큐에 추가됩니다.
  4. bazThird를 남깁니다. 이벤트 루프는 baz가 반환된 후 콜 스택이 비는지 확인한 뒤에 콜백을 콜 스택에 추가합니다.
  5. 콜백은 Second를 남깁니다.

이벤트 루프를 좀 더 편안하게 받아들여졌기를 바랍니다! 여전히 이것들이 좀 어려워보이더라도 걱정하지 마세요. 가장 중요한 것은 효율적으로 구글링을 하기 위해서 특정 오류나 동작이 발생할 수 있는 위치를 이해하고 적절한 StackOverflow 페이지를 찾아내는 겁니다. 💪🏼 궁금한 점이 있으면 언제든지 질문 주세요!