[TIL 0421] Macro task queue(매크로 태스크 큐) vs Micro task queue(마이크로 태스크 큐)

zitto·2023년 4월 21일
0

TIL

목록 보기
62/77
post-thumbnail

Promise로 실행하는 함수는 태스크 큐에 들어간다.
태스크 큐는 딱 하나만 있는 것이 아니라, 여러 개가 동시에 존재한다.


✔️ Task Queue 종류

  • 매크로 태스크 큐 (MacroTaskQueue)
    setTimeout, setInterval 등이 들어가는 큐
  • 마이크로 태스크 큐 (MicroTaskQueue)
    Promise 등이 들어가는 큐

마이크로 태스크 큐가 우선순위를 가진다.


✔️ 태스크 큐들 간의 실행 우선순위

[실습 section 29-04]

<!DOCTYPE html>
<html lang="ko">
  <head>
    <title>EventLoop</title>
    <script>
      const onClickLoop = () => {
        console.log("start!!");
        //비동기작업(macro queue에 들어감)
        setTimeout(() => {
          //비동기작업(micro queue에 들어감)
          new Promise((resolve) => resolve("setTimeout")).then(() => {
            console.log("Promise (setTimeout안에서 실행!) ");
          });
          console.log("setTimeout , macro queue, 0초 뒤 실행");
        }, 0);
        //비동기작업(micro queue에 들어감)
        new Promise((resolve) => resolve("Promise 1")).then(() => {
          console.log("Promise 1 , micro queue , 0초 뒤 실행!");
        });
        //비동기작업(macro queue)
        setInterval(() => {
          console.log("setInterval , macro queue, 0초 마다 실행");
        }, 0);
        // 오래걸림
        let sum = 0;
        for (let i = 0; i <= 9000000000; i++) {
          sum += 1;
        }
        //비동기작업(micro queue에 들어감)
        new Promise((resolve) => resolve("Promise 2")).then(() => {
          console.log("Promise 2 , micro queue , 0초 뒤 실행!");
        });
        console.log("finish!");
      };
    </script>
  </head>
  <body>
    <button onclick="onClickLoop()">START</button>
  </body>
</html>


✔️ await와 Micro queue의 관계

isSubmitting을 활용한 중복뮤테이션 방지


[실습 section29-05]

import axios from "axios";
import { useState } from "react";
import { wrapAsync } from "../../../src/commons/libraries/asyncFunc";
export default function RestGetPage(): JSX.Element {
  const [isSubmitting, setIsSubmitting] = useState(false);
  //게시글 등록하기 버튼으로 가정!
  const onClickSync = async (): Promise<void> => {
    // 등록하는 동안은 등록버튼이 작동하지 않도록
    setIsSubmitting(true); //제출 중
    const result = await axios.get("https://koreanjson.com/posts/1");
    console.log(result);
    console.log(result.data.title);
    // 등록이 완료되었다면 다시 버튼이 동작하도록
    setIsSubmitting(false);
  };
  return (
    <div>
      {/* 유저가 연타클릭시 중복게시글이 등록될 수 있음 따라서 막아줘야함! */}
      <button onClick={wrapAsync(onClickSync)} disabled={isSubmitting}>
        REST-API(동기)요청하기
      </button>
    </div>
  );
}

클릭할때마다 작동됨!
state 만들어서 연타막기!

함수가 끝날때 state가 바뀌는데
true라고 해서 임시저장공간에 들어감. 바로 안바뀜
근데?

setState는 함수 내부에서 여러번 사용되도 제일 나중에 바뀐걸로 최종 반영해준다고 알고 있는데 둘다 작동됨

이유?
함수가 사실 await에서 끝남
await 만나는 순간 async이 마이크로큐로 가고
그때 함수가 한번 끝남!
그전까지 있떤 true를 반영해서 리렌더링
그리고 다시 마이크로큐에 있던게 콜스택으로 올라와서
result에 담고 setIsSubmitting(false);로 됨
두번의 State 업뎃이 이뤄짐


[quiz - 1]

<!DOCTYPE html>
<html lang="ko">
  <head>
    <title>이벤트루프</title>
    <script>
      function onClickLoop() {
        console.log("=======시작!!!!=======");
        function aaa() {
          console.log("aaa-시작");
          bbb();
          console.log("aaa-끝");
        }
        async function bbb() {
          console.log("bbb-시작");
          const friend = await "철수";
          console.log(friend);
        }
        aaa();
        console.log("=======끝!!!!=======");
      }
    </script>
  </head>
  <body>
    <button onclick="onClickLoop()">시작하기</button>
  </body>
</html>

▼ 예상결과

//예측하기
=======시작!!!!=======
aaa-시작
bbb-시작
철수
aaa-=======!!!!========

▼ 실제결과

▼ 과정

  1. aaa()함수가 실행되고 "aaa-시작"콘솔이 출력
  2. aaa()함수 내 bbb()가 실행되어서 bbb()함수 내부 실행되고
    "bbb-시작"을 콘솔에 출력
  3. "철수"라는 `await 를 만나게 되는 순간 async를 감싸고 있는 function 즉, bbb() 함수가 하던일을 중단하고 마이크로 큐에 들어가게 된다.
  4. bbb()함수가 스택에서 사라졌으니 다음 "aaa-끝"를 콘솔출력
  5. 다음 onClickLoop의 "=======끝!!!!=======" 출력을 하고
  6. 마지막에 마이크로큐에 들어가있는 기다리고 있던 "철수"가 다시 스택으로 들어와 출력되는 것임.

[quiz - 2]

<!DOCTYPE html>
<html lang="ko">
  <head>
    <title>이벤트루프</title>
    <script>
      function onClickLoop() {
        console.log("=======시작!!!!=======");
        function aaa() {
          console.log("aaa-시작");
          bbb();
          console.log("aaa-끝");
        }
        async function bbb() {
          console.log("bbb-시작");
          await ccc(); // 힌트: ccc()가 먼저 실행되고 await가 진행됩니다.
          console.log("bbb-끝");
        }
        async function ccc() {
          console.log("ccc-시작");
          const friend = await "철수";
          console.log(friend);
        }
        aaa();
        console.log("=======끝!!!!=======");
      }
    </script>
  </head>
  <body>
    <button onclick="onClickLoop()">시작하기</button>
  </body>
</html>

▼ 실제결과

  1. onClickLoop함수가 실행되고 "=======시작!!!!=======" 출력
  2. aaa함수 실행되서 "aaa-시작"출력, bbb() 함수 실행되고,
    "bbb-시작" 출력됨.
  3. ccc()함수가 실행되고 "ccc-시작" 출력됨
  4. 다음 await "철수"를 만나고 컴퓨터는 언제까지 기다리라는 건지 모름
  5. 따라서 async가 감싸고 있는 함수(ccc)가 마이크로 큐에 들어가며 실행하던 위치를 기억한다.
  6. 이어 bbb()함수도 두번째로 마이크로 큐에 들어가게 됨.
  7. bbb가 끝났으니 aaa함수의 "aaa-끝"가 출력되고
    함수가 끝났으니 "=======끝!!!!======="출력
  8. 마이크로큐에 있던 ccc부터 스택에 들어와서 "철수"가 출력됨
  9. 마지막으로 "bbb-끝"가 출력되는 것임!

실행하다 await 만나면 그걸 감싸고 잇는 async function이 마이크로큐에 저장됨!!!

await는 Promise를 기다리는 역할인데
그게 가능한 이유는
axios 자체가 new Promise임
Promise는 마이크로큐에 감
await를 만나니 그걸 감싼 async(onClickSync)도 마이크로 큐에 들어감

그래서 빠져나올때도 axios가 먼저,
axios 끝날때까지 onClickSync는 실행안됨

try / catch

트라이에서 강제로 에러발생가능하다.

마이크로큐에 들어가고 콘솔에 철수찍어서 아무일도 안일어나니
aaa함수 종료
에러 발생안나옴 왜? aaa함수 종료해서!
만약 캐치해서 잡고싶다?
그럼 await가 필요함

profile
JUST DO WHATEVER

0개의 댓글