
뜬금 없이 힙과 호출스택을 하다가 태스크큐와 마이크로태스크큐를 공부하는 것 같다.
하지만 이전 포스트에서 사용한 사진에서 보면

웹을 실행시키기 위해선 메모리, 힙을 제외하고도 콜백 큐(Callback Queue)도 필요하다.
찾아보니 콜백 큐라는 단어에 대해선 말이 나뉘었다.
- 콜백 큐에 태스크 큐와 마이크로태스크 큐가 들어있다.
- 콜백 큐는 태스크 큐의 다른 이름이다.
2번은 해외 레퍼런스에서 여러번 나왔다.
그래서 나는 2번이라고 생각하고 이야기 하겠다.
(사실 포스트 작성하고 보니 더 이상 콜백 큐라고 지칭할 일이 없더라...)
그럼 태스크 큐와 마이크로태스크 큐가 하는 일은 무엇일까?
마이크로태스크 큐는 어떤 일을 할까?
마이크로태스크 큐는 Promise와 MutationObserver의 콜백 함수를 담는다.
MutationObserver?
MutationObserver는 DOM의 속성, 텍스트, 자식 노드들에 대한 변경을 감지할 수 있는 API이며, 특정 노드 객체를 관찰하고, 변경이 발생했을 때 콜백 함수를 실행한다.
하지만 여기서 MutationObserver 는 중요하지 않다.
마이크로태스크 큐가 어떤 일을 하는지는 코드로 확인해보자.

이제 위의 코드 정도는 눈을 감고도 해석할 수 있다.
위의 코드가 어떤 순서로 실행되는지 한 번 생각해보자. 답은 아래에 있다.
Velog가 접기 펼치기 기능이 없어 공백으로 채운다...
답은...?

내가 처음 Promise에 대해 배웠을 때는 나는 1 -> 나는 3 -> 나는 2 -> 프로미스 Resolve 순서로 실행될 것이라고 생각했지만 아니었다;;
그럼 저 코드가 마이크로태스크 큐와 호출스택에서 어떻게 담기는지 확인해보자.










다시 한 번 마이크로태스크 큐에 대해서 말해보면
마이크로태스크 큐는 Promise와 MutationObserver의 콜백 함수를 담는다.
여기서 말하는 콜백 함수는 new Promise((res, rej)=>{...}) 의 콜백 함수가 아니라.
.then(()=>{}) 의 콜백 함수를 말하는 것이었다...
이벤트 루프란 태스크 큐와 마이크로태스크 큐, 호출 스택을 계속해서 감시하며,
호출 스택이 비어있을 때 태스크 큐와 마이크로태스크 큐에서 콜백함수를 하나씩 꺼내어 호출 스택에 넣어준다.
위에서 큐에 대해서 공부하고 이벤트 루프를 보니 이제 이해가 가는 것 같다.
아래의 태스크 큐도 같이 공부해보면서 확인해보자.
음... 보기엔 마이크로태스크 큐 혼자만 있어도 충분할 것 같은데 태스크 큐는 다른 역할을 하나?
태스크 큐는 setTimeout(), DOM 이벤트 또는 Fetch 요청과 같은 비동기 작업을 담는다.
위의 API들은 전부 WebAPIs 들이다. 이 WebAPIs 는 단일 스레드로 동작하는 자바스크립트에서 멀티 스레드처럼 동작해야 하는 것들이다.
예를 들어 setTimeout(()=>{}, 2000) 라고 작성하면 setTimeout에 의해 생성되는 타이머 객체가 다른 호출 스택에 쌓여서 2초를 보내야 하기 때문이다.
그런데 그러지 않고 만약 단일 스레드로만 동작하면
- setTimeout 실행.
- setTimeout이 태스크 큐에 적재.
- 다른 명령어들 전부 수행하여 호출 스택 비어 있음.
- setTimeout이 스택에 쌓임.
- 겨우 스택에 쌓이고 나서야 2초를 보냄.
- 그 후 setTimeout에 전달한 콜백 함수를 실행.
이런 식으로 실행되기 때문에 다른 곳에서 2초를 미리 보내놓고 호출 스택에 담기자마자 실행하는 효과를 얻을 수가 없다.
이 setTimeout가 수행하는 멀티스레드 역할을 웹 브라우저에서 대신 해준다.
갑자기 태스크 큐 얘기 하다가 말고 무슨 멍소리하냐... 라고 할 수 있지만
이러한 배경을 가지고 코드가 어떻게 실행되어 태스크 큐에 적재되는지 확인해보자.

우선 이 코드가 어떤 순서로 출력될지 예상해보자.
참고로 첫 번째 Promise는 setTimeout으로 resolve를 감쌌지만 0초를 줬기 때문에 딜레이는 없다.
그리고 for문을 사용한 이유는 promise1() 와 promise2() 의 실행 사이에 적당한 텀을 주기 위해서다.
어떤 순서로 실행될까?
접기/펼치기 기능 만들어주세요...
정답은

처음 공부할 때 내가 예상했던 것은 나는 1 -> 나는 3 -> 나는 2 -> 프로미스2 -> 프로미스1 순서일 것이라 생각했다.
하지만 아니었다.
우선 왜 그런지 미리 얘기하자면 태스크 큐는 마이크로태스크 큐보다 우선순위가 떨어진다.
이것을 가지고 어떻게 태스크 큐와 마이크로 태스크 큐에 적재되는지 그림으로 보자.















해당 포스트에서 작성하려고 했으나 다음 포스트인 틀린 코드 고치기의 1.1 에서 틀린 코드가 async/await을 사용하고 있으므로 거기서 같이 알아보자.
| 태스크 큐 | 마이크로태스크 큐 | |
|---|---|---|
| 무엇이 담기나 | DOM 이벤트, setTimeout, fetch 등 WebAPIs | Promise와 MutationObserver의 콜백 함수 |
| 우선순위 | 낮음 | 높음 |
| 얼마나 | 비우는 도중 마이크로태스크 큐에 함수가 담긴다면 멈춤 | 비우기 시작하면 전부 비울때까지 비움. |