반응형
출처: "You don’t know JavaScript until you can beat this game"
- https://javascript.plainenglish.io/you-dont-know-javascript-until-you-can-beat-this-game-aa7fd58befb
- [You don’t know JavaScript until you can beat this game]
자바스크립트 이벤트 루프 공부에 아주좋은 미니퀴즈
풀어보고 잘못알고있던부분에 대해 번역 겸 정리해보자
콘솔에 찍히는 순서는?
(Race 1,2는 맞춰서 생략)
Race 3.
setTimeout(() => console.log("Horse A"), 0);
wait60Seconds(); //some incredibly expensive synchronous computation
console.log("Horse B")
- 답: Horse B, Horse A
- setTimeout이 웹 API이지만 0초라서 바로 끝난다. 하지만 그 사이에 콜스택에서 60초를 기다리고 있다. 콜스택에서 60초가 끝나더라도 자바스크립트는 Sync operation을 항상 먼저 수행해야 한다. 때문에 0초 timeout이 끝나고 task queue에서 대기하고있던 "Horse A"는 "Horse B"가 실행되고 콜스택이 비워졌을 떄, 비로소 큐에서 나와 콜스택으로 들어가게 된다. 그리고 실행된다.
Race 4.
const asyncOperation = fetch('something.com');
asyncOperation.then((resolvedValue) => console.log("Horse A"));
console.log("Horse B")
- 답: Horse B, Horse A
- fetch 동작에 대해 알아야 한다. fetch는 프로미스 객체를 반환하는 브라우저 API이다. 그러니까 콜스택에서 나와서 백그라운드에서 네트워크 통신을 해서 원하는 데이터를 가져온다. 그 사이에 sync operation은 실행되어 진다.
.then
은 fetch가 데이터를 가져와서 resolved되어지면, 프로미스를 반환하고, 그 프로미스의 value속성이 업데이트된다. 이 프로미스는 onFulfilled속성도 가지고 있는데 .then으로 받아온 함수(여기에서는 Horse A)가 onFulfilled속성으로 푸시되어진다. 즉, "Horse A"는 사실 우리가 받은 프로미스의 onFulfilled속성으로 들어가있고, resolved되어서 데이터를 받으면 프로미스의 value속성이 업데이트 된다. onFulfilled는 이 value를 자동으로 받아서 실행된다! - 이러니까 .then보다 .whenverThisValueGetsResolved라는 네이밍이 되어야 한다..(내가 한 말아니고 번역한 것)
fetch..복잡한 녀석이었군
하지만 단순히 말하자면 fetch는 브라우저 API라서 백그라운드에서 실행되고, 그 사이에 "Horse B"는 이미 실행된다. fetch가 반환한 프로미스를 받아오고 이 프로미스가 resolved되면, 이 프로미스의 onFulfilled속성으로 푸시된 "Horse A"가 실행된다.
Race 5.
setTimeout(() => console.log("Horse A"), 0);
const promise = Promise.resolve();
promise.then(() => console.log("Horse B"));
console.log("Horse C")
- 답: C,B,A
- 일단, A,B는 브라우저 API라서 C가 먼저 실행된다. A와 B는 시간 딜레이는 없지만, task queue에 들어갈 때, fetch의 콜백으로 등록된 함수는 Microtask queue에 들어가고, setTimeout콜백은 (normal) task queue에 들어간다. fetch 콜백함수가 우선적으로 실행되야하기 때문에, Microtask queue에 있는 함수들을 콜스택으로 모두 옮겨 콜스택이 비워지면 task queue에 있는 함수들이 같은 절차로 실행된다.
Race 6.
setTimeout(() => console.log("Horse A"), 5)
const promise = new Promise((resolve) => {
setTimeout(() => resolve(), 10)
})
promise.then(() => console.log("Horse B"))
console.log("Horse C")
- C,A,B
- 일단 브라우저 API가 아닌 C가 먼저 실행. 백그라운드로 setTimeout 5초가 실행되고 task queue에 "Horse A"가 들어간다. 프로미스는 즉시 resolved되어 setTimeout을 실행시키고 microtask queue에 넣는다. .then의 콜백함수도 실행되어 queue에 들어간다. 하지만 10ms의 딜레이가 필요하기 때문에, 그 사이 이미 5ms가 지나서 큐에 들어가있는 A는 우선적인 microtask queue가 비어있음을 확인하고 "Horse A"를 실행한다.
The final Race
setTimeout(() => console.log("Horse A"), 0);
const promise = fetch("someUrl") // takes 100ms
promise.then(x => console.log("Horse B"));
waitFor200ms();
console.log("Horse C");
- 답: C,B,A
- 일단, setTimeout콜백함수는 task queue에 들어간다. 100ms후에 then 콜백함수도 microtask queue에 들어간다. waitFor200ms를 확인한 자바스크립트는 콜스택에서 200ms함수를 실행한다. 그리고 이어서 C를 실행한다. 그리고 이제 200ms가 지나서 setTimeout, then 콜백 각각 queue에 들어가있다. microtask먼저 실행되므로 B,A이다.
- 근데 A가 완료되고 다음라인을 볼 떄 async오퍼레이션이니까 큐에있는 A를 먼저 실행할수있는거 아닌가? 하지만 스크립트를 읽어나가는 속도가 훨씬 빠르기 때문에 fetch를 실행하려고 할때는 아직 큐에 들어가있지 않는다고 보는..것인가. 일단 ㅇㅋ
하고보니 엄청 헷갈렸는데, 글로쓰니까 순서가 딱 정리되었다.
이벤트 루프 녀석,,, 쉽지않군,,
혹시 틀린부분이 있다면 신랄하게 지적해주십시오,,,
반응형
'Web Development' 카테고리의 다른 글
[기술문서] 리액트 headless 컴포넌트와 디자인시스템을 위해 UI 라이브러리 사용을 중단한 이유 (0) | 2023.06.10 |
---|---|
styled-icon color가 변경 삽질기 & 해결방법 (0) | 2022.03.15 |
callback 함수를 왜 쓰나? (0) | 2022.01.07 |
var 변수와 스코프 (0) | 2022.01.07 |
자바스크립트의 특징; 인터프리터, 명령형, 함수형, 프로토타입 기반 객체지향 언어 ? (0) | 2022.01.03 |