queueMicrotask() 사용하여 스케쥴링하기

microtask queue & macrotask queue

https://developer.mozilla.org/ko/docs/Web/API/HTML_DOM_API/Microtask_guide

마이크로태스크를 사용해야할 때

조건적 프로미스 사용에 있어서 실행 유지 😲

customElement.prototype.getData = (url) => {
  if (this.cache[url]) {
    this.data = this.cache[url];
    this.dispatchEvent(new Event("load"));
  } else {
    fetch(url)
      .then((result) => result.arrayBuffer())
      .then((data) => {
        this.cache[url] = data;
        this.data = data;
        this.dispatchEvent(new Event("load"));
      });
  }
};

위 함수를 아래와 같은 환경에서 두번 실행해보면

element.addEventListener("load", () => console.log("Loaded data"));
console.log("Fetching data...");
element.getData();
console.log("Data fetched");

캐시 없을 때 (else 절로 넘어감)

Fetching data...
Data fetched
Loaded data

캐시 있을 때 (if 절로 넘어감)

Fetching data...
Loaded data
Data fetched
customElement.prototype.getData = (url) => {
  if (this.cache[url]) {
    queueMicrotask(() => {
      this.data = this.cache[url];
      this.dispatchEvent(new Event("load"));
    });
  } else {
    fetch(url)
      .then((result) => result.arrayBuffer())
      .then((data) => {
        this.cache[url] = data;
        this.data = data;
        this.dispatchEvent(new Event("load"));
      });
  }
};

계산 배칭 😳👍

const messageQueue = [];

let sendMessage = (message) => {
  messageQueue.push(message);

  if (messageQueue.length === 1) {
    queueMicrotask(() => {
      const json = JSON.stringify(messageQueue);
      messageQueue.length = 0;
      fetch("url-of-receiver", json);
    });
  }
};

  1. sendMessage()를 호출하면 주어진 메시지는 우선 messageQueue 배열에 들어간다.
  2. 방금 배열에 추가한 메시지가 첫번째 메시지라면 sendMessage 는 메시지 전송 배치를 예약한다. (아직 콜스택 내의 실행할게 남아있으므로 바로 보내진 않음)
  3. 그리고 sendMessage 가 계속 호출되고 여러 메시지들을 messsageQueue 배열에 넣겠지만 마이크로태스크큐로 배치를 예약하진 않는다 (길이 검사로인해)
  4. 그리고 이렇게 실행컨텍스트가 끝난 후, 마이크로태스크 실행 시점이 오면..! 마이크로태스크는 우선 JSON.stringify로 메시지를 JSON으로 바꾸고, 배열을 비운다.
  5. 이를 통해 이벤트 루프의 같은 주기에서 수행한 sendMessage()다수의 호출은 하나의 fetch에 모이게 되고, 타임아웃이나 통신 지연을 피할 수 있음.