230502_TIL

majungha·2023년 5월 2일
1

TIL

목록 보기
45/68

앞으로의 목표 👍


  1. javascript 능력 및 고난도 알고리즘 풀이 능력
  2. Nest, Graphql등 최신 기술 스택 활용 능력
  3. 기초 미니프로젝트 포트폴리오
  4. 로그인, 결제기반 심화프로젝트 포트폴리오
  5. 배포를 위한 네트워크 및 CI/CD 배포자동화 능력
  6. 120% 백엔드 개발 지식

오늘부터 꾸준히 해야할 일 👍


  • 영타실력 늘리기
  • 단축키 사용 익숙해지기
  • 코드리딩 실력 키우기
  • 데일리 퀴즈
  • 포트폴리오 작성
  • 독스에 친숙해지기
  • MDN 보는 연습하기

오늘의 수업 👍



📝 마이크로태스크 큐 vs 매크로태스크 큐 (JavaScript 심화 - 이벤트루프)


const onClickLoop = () => {
  console.log("시작!!!");

  setTimeout(() => {
    console.log("0초 뒤에 실행된다!!!");
  }, 0);

  let sum = 0;
  for (let i = 0; i <= 9000000000; i++) {
    sum += i;
  }

  console.log("끝!!!");
};
  • 위와 같은 함수가 있을 때 실행 순서를 예상해보면

    1. 시작!!!
    2. 0초뒤에 실행된다!!
    3. for문 실행
    4. 끝!!!
  • 위와같은 순서로 실행될 것 같지만 실제로는 아래의 순서로 실행된다.

const onClickLoop = () => {
  console.log("시작!!!");

  // 비동기작업(콜백함수가 매크로큐에 들어감)
  setTimeout(() => {
    new Promise((resolve) => resolve("철수")).then(() => {
 	  console.log("저는 Promise(setTimeout 안에서 실행될 거예요!!!)");
    });
   console.log("저는 setTimeout!! 매크로큐!! 0초 뒤에 실행될 거예요!!!");
  }, 0);

  // 비동기작업(콜백함수가 마이크로큐에 들어감)
  new Promise((resolve) => resolve("철수")).then(() => {
    console.log("저는 Promise(1)!! 마이크로큐!! 0초 뒤에 실행될 거예요!");
  });

  // 비동기작업(콜백함수가 매크로큐에 들어감)
  setInterval(() => {
    console.log("저는 setInterval!! 매크로큐!! 0초마다 실행될 거예요!!!");
  }, 0);

  let sum = 0;
  for (let i = 0; i <= 9000000000; i++) {
    sum += i;
  }
  console.log(`sum = ${sum}`);

  // 비동기작업(마이크로큐에 들어감)
  new Promise((resolve) => resolve("철수")).then(() => {
	console.log("저는 Promise(2)!! 마이크로큐!! 0초 뒤에 실행될 거예요!");
  });

  console.log("끝!!!");
};
  • 마찬가지로 위와같은 함수가 있을 때 실행 순서를 예상해 보면
    1. 시작!!!
    2. 저는 Promise(setTimeout 안에서 실행될 거예요!!!)
    3. 저는 setTimeout!! 매크로큐!! 0초 뒤에 실행될 거예요!!!
    4. 저는 Promise(1)!! 마이크로큐!! 0초 뒤에 실행될 거예요!
    5. 저는 setInterval!! 매크로큐!! 0초마다 실행될 거예요!!!
    6. 저는 Promise(2)!! 마이크로큐!! 0초 뒤에 실행될 거예요!
    7. 끝!!!
  • 위와같은 순서로 실행될 것 같지만 실제로는 아래의 순서로 실행된다.
  • 이렇게 순서가 다르게 발생된 이유는 이벤트 루프에 대한 개념이 필요하다.

▶ 이벤트 루프

  • 콜 스택에 있는 함수들의 실행이 완료되면, 이벤트 루프에 의해 콜 스택이 비었음을 알게 되고, 태스크 큐에서 대기 중인 콜백 함수를 이벤트 루프에 의해 콜 스택에 보내져 실행이 되게 된다.
  • 태스크 큐에는 마이크로큐와 매크로큐가 존재한다.
  • 매크로큐보다 마이크로큐에 더 급한 요청들이 존재하기에, 매크로큐에 요청이 많아도 마이크로큐의 요청이 존재한다면 마이크로큐 요청이 먼저 처리되며, 마이크로큐 요청이 다 처리되어서 비어있다면 그때 매크로큐의 요청을 처리하게 된다.

▷ async-await 와 마이크로 큐의 관계 (1)

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("=======끝!!!!=======");
}
  • 위와같은 함수가 있을 때 실행 순서를 예상해 보면
    1. =======시작!!!!=======
    2. aaa-시작
    3. bbb-시작
    4. 철수
    5. aaa-끝
    6. =======끝!!!!=======
  • 위와같은 순서로 실행될 것 같지만 실제로는 아래의 순서로 실행된다.
  • 이렇게 순서가 다르게 발생된 이유는 await 와 마이크로태스크 큐에 대한 개념이 필요하다.

▶ await 와 마이크로태스크 큐

  • await를 만나게 되면, async가 붙은 bbb 함수 자체가 Promise 로 변하게 되면서,
  • bbb 함수가 즉시 중단되고, bbb 함수 내부의 실행되지 못한 나머지 함수들은 마이크로큐로 들어가게 된다.
  • 따라서, 콜스택에서 실행 중이던 bbb 함수는 콜스택에서 제거 된다.

▷ async-await 와 마이크로 큐의 관계 (2)

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("=======끝!!!!=======");
}
  • 위와 같은 함수의 실행결과는 아래와 같다.

  • 이유
    • await(await "철수” 의 await)를 만나게 되면, async가 붙은 ccc 함수 자체가 중단되고, 실행되지 못한 ccc 함수들은 마이크로 태스크큐로 이동 된다.
    • ccc 함수가 중지되고 bbb 함수가 실행되는데, 또 다시 await(await ccc() 의 await) 를 만나게 된다.
    • 따라서, async가 붙은 bbb 함수가 중단되고 마이크로 태스크큐로 이동 된다.
  • 일반적으로 에러 처리는 try ~ catch 문을 통해서 하게 됩니다.
  • 하지만, 비동기 처리 함수들은 호출자가 없기에, try ~ catch 문을 사용하여 에러를 핸들링 하기 어렵다.
    • 콜 스택의 아래 방향으로 에러가 전파되는데, 비동기 함수들은 콜 스택이 비어있을 때 이벤트 루프에 의해 콜 스택으로 이동되어 함수가 실행되기에 콜 스택의 가장 하부에 함수가 존재하고 있으므로 에러를 전파할 호출자가 존재하지 않기 때문에 에러 핸들링을 하기 어려운 것이다.

▷ await와 마이크로큐에 기반한 try~catch 동작 원리

const onClickCatchFail = () => {
  try {
	axios.get("https://qqqqq.com");
	console.log("철수"); // 로그까지 찍고, aaa 함수 정상 종료
  } catch (error) {
	console.log("에러가 발생하였습니다!");
  }
};

const onClickCatchSuccess = async () => {
  try {
	await axios.get("https://qqqqq.com");
	console.log("철수");
  } catch (error) {
    console.log("에러가 발생하였습니다!");
  }
};
  • 위와 같은 함수가 있을 때

  • 첫번째 함수는 아래와 같은 이유로 에러를 잡지 못한다.

    1. Promise인 axios가 마이크로큐에 들어가고 try는 정상 종료되고, aaa 함수도 정상 종료된다.
    2. 마이크로큐에 있던 axios가 콜스택으로 돌아왔을 때 try-catch는 아까 정상 종료되었으므로 실패해도 못잡는다.
  • 두번째 함수는 아래와 같은 이유로 에러를 잡는다.

    1. Promise인 axios가 마이크로큐에 들어감. aaa함수도 await를 만나서 마이크로큐에 들어간다.
    2. 마이크로큐에 있던 axios가 콜스택으로 돌아왔을 때 try-catch가 포함된 aaa 함수도 다음 마이크로큐에서 대기중이므로 실패하면 잡힌다.
  • 첫번째 함수는 에러를 못잡고 두번째 함수는 에러를 잡는 이유

    • 콜스택에서 함수를 실행하다가 await 를 만나게 되면 async가 붙은 aaa 함수 자체가 중단되고 마이크로 태스크큐로 이동한다.
    • try 문의 실행이 완료되지 않은 상태이기 때문에, try ~ catch 문도 함께 마이크로 태스크큐로 이동되는 것이다.
    • 이후, 콜스택이 비어있는 것을 확인한 이벤트 루프에 의해 aaa 함수는 콜스택으로 이동되어 aaa 함수가 실행된다.
    • 현재 자바스크립트 엔진의 콜스택 내에는 try ~ catch 도 존재하기에, axios 함수가 제대로 실행되지 않으면 에러를 캐치하여 콘솔이 실행되게 되는 것이다.

오늘의 마무리 👍



  • 복습
  • github 공부
  • 블로그 포스팅
  • 데일리 퀴즈
  • 알고리즘 문제 풀기

항상 겸손한 자세로 배우면서 성장하자, 할 수 있다!! 💪


출처 : 코드캠프

profile
개발자 블로그 / 항상 겸손한 자세로 배우면서 성장하자 할 수 있다!

0개의 댓글