본문 바로가기

카테고리 없음

[TIL] JS스터디-promise

왜 Promise로 비동기를 관리하려는가.

promise는 js에서 비동기 상황을 효율적으로 처리하는 데 사용되는 개념이다.

효율적이라는 말은, 기존에 비동기 상황을 다루기위해선 콜백 함수를 전달하여 비동기 결과값을 사용할 수 있었다.

이렇게 되면 비동기 결과값을 연속적으로 사용하려면 콜백 함수를 계속 전달하게 되어 뎁스가 깊어지고, 코드를 읽는 방식이 아래에서 위로 읽히게 되어 가독성이 떨어지는 문제가 발생한다.

또한 에러 핸들링관련해서도 콜백 함수마다 try catch문을 내부에서 작성해줘야 하기 때문에 코드 자체가 복잡해지는 문제가 발생한다.

    try {
        setTimeout(() => {
          throw new Error("error");
        }, 1000);
      } catch (error) {
        console.log(error);
      }

위와 같이 작성하게 되면 setTimeout함수에 전달된 콜백 함수가 실행되는 과정에서 오류가 발생해도 catch문에서 잡히지 않는다.
따라서 아래와 같이 콜백함수 내부에서 try catch문을 추가로 작성해줘야 하는 번거로움이 발생한다.

       try {
        setTimeout(() => {
          try {
            throw new Error("error");
          } catch (error) {
            console.log(error);
          }
        }, 1000);
      } catch (error) {
        console.log(error);
      }

따라서 이러한 콜백헬,에러처리문제로인해 비동기를 promise로 다루는 방식이 등장했다.

promise로 어떻게 비동기를 처리하는가 ( + catch로 에러를 핸들링하는 이유)

에러 없이 진행된 상황을 resolve함수가, 에러가 발생된 상황을 reject함수가 호출된다. 이를 일반적인 참조로는 값을 참조할 수 없고, then메서드의 콜백 함수의 인자로 해당 상황의 값이 전달되어 이를 콜백 함수 내부에서 참조할 수 있게 된다. 흔히 then은 성공할 때, catch는 실패할 때 참조할 수 있는 것으로 알고 있는데 catch는 then(undefined, onRejected)와 동일하게 동작한다. 그리고 then의 두 번째 인자로 에러를 핸들링하지 않는 이유로는 then의 첫 번째 인자로 전달된 콜백 함수에서 발생된 에러를 두 번째 인자에서 핸들링할 수 없기 때문이다. 추가적으로 then은 성공, catch는 에러 이렇게 구분 지어 코드를 작성하는 편이 좀 더 가독성이 좋을 것 같다라는 생각도 든다.
이런 이유 때문에 then의 2번째 인자보단 catch로 에러를 핸들링하는 편이 좀 더 안정적이다.

 const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve("성공");
        }, 1000);
      });

      promise.then(
        (success) => {},
        (error) => {
          // then의 첫번째 인자로 전달된 콜백함수내에서 발생된 에러를 여기선 캐치할 수 없게됨.
        }
      );

then은 언제 실행되는가?

promise에는 pedding상태와 settled상태가 존재한다. pendding은 아직 성공, 실패가 아닌 상태를 의미(비동기가 진행 중인 상태)하고 settled는 둘 중에 어느 상황이든 판정 이난 상황을 의미힌다.
then은 settled상태로 promise가 전환되면 호출이 된다.

마이크로 태스크 큐는 뭔가? 태스크 큐와 다른 점은?

태스크 큐는 setTimeout, setInterval, addEventListener 등등에 등록되는 콜백 함수를 처리하는 큐다.
마이크로 태스크 큐는 promise의 then 등등에 전달되는 콜백 함수가 처리되는 큐다.

우선 둘 다 콜 스택이 비워져 있을 때 이벤트 루프에 의해 큐(FIFO구조)에서 콜 스택으로 이동된다.

차이점

1. 태스크 큐는 현재 처리하는 콜백 함수 외의 함수가 태스크 큐에 존재하더라도 이벤트 루프에 의해 한번에 하나씩 처리되고(화면정지 현상 x) 마이크로 태스크 큐는 큐에 있는 모든 함수가 처리될 때까지 이벤트 루프가 마이크로 태스크 큐에서 대기한다.(화면 정지 현상 발생)

 

2. 태스크 큐와 마이크로 태스크 큐 모두에 콜백 함수가 등록되어있으면 마이크로 태스크 큐에 등록된 함수를 우선적으로 콜 스택에 전달시킨다.

setTimeout(() => console.log(1), 0); 

Promise.resolve() 
	.then(() => console.log(2)) 
	.then(() => console.log(3))

1 -> 2 -> 3 순이 아닌, 2 -> 3 -> 1 순으로 출력된다.
그 이유는 위에서 언급한 바와 같이 전역 실행 컨택스트가 종료되어 콜 스택이 비워졌을 시기에 태스크 큐에 등록된 setTimeout함수의 콜백함수와 마이크로 태스크큐에 등록된 then콜백함수가 동시에 존재함으로 우선순위에따라 마이크로 태스크 큐에등록된 콜백 함수를 처리하게 된다.