Promise

contability·2024년 1월 30일
0

자주 쓰면서도 제대로 알아본적이 없어 적어둔다.


Promise는

비동기 작업의 완료와 그 결과 값을 나타낸다.

비동기 액션의 최종 성공 혹은 실패의 값과 핸들러를 연결할 수 있다.
이것을 통해 비동기 메서드는 최종 값을 즉시 반환하는 대신 미래의 어느 시점에 값을 제공하겠다는 약속을 반환하는 동기 메서드처럼 값을 반환할 수 있다.

Promise의 상태 값


  • 보류(pending): 완료 되지도 거부 되지도 않은 초기 상태.
  • 완료(fulfilled): 작업이 성공적으로 완료됨.
  • 거부(rejected): 작업이 실패했음.

보류 중인 Promise의 최종 상태는 성공 값 혹은 실패 이유이며
이 중 하나가 발생하면 Promise의 then 메서드에 의해 대기 중인 관련 핸들러가 호출된다.

resolved


Promise와 함께 해결(resolved)라는 용어가 자주 사용되는데 이것은 Promise가 결정되거나 다른 Promise의 최종 상태와 일치하도록 고정 되었음을 의미한다. 또한 이후에 이를 다시 결정하거나 거부하는 것은 아무런 효과가 없다.

new Promise((resolveOuter) => {
  resolveOuter(
    new Promise((resolveInner) => {
      setTimeout(resolveInner, 1000);
    }),
  );
});

이 Promise는 생성될 때 이미 resolved 상태이다.
이유는 resolveOuter가 동기적으로 호출되기 때문이다.

하지만 이 Promise는 다른 Promise로 resolved 되었고, 따라서 내부 Promise가 이행될 때인 1초 후까지 완료되지 않는다.
실제로 resolution은 종종 뒤에서 일어나고 관찰할 수 없으며, 완료 또는 거부만이 관찰된다.

쉽게, Promise가 resolved 상태라는 것은 Promise의 결과가 이미 결정되었지만, 그 결과가 어떤 것인지(완료 or 거부)는 아직 알 수 없다는 것을 의미한다.

위 예시에 바깥쪽 Promise는 생성과 동시에 resolved 되었지만, 그 안쪽 Promise가 완료되는건 1초 후에야 결정된다.

Chained Promises


Promise.prototype.then(), Promise.prototype.catch(), Promise.prototype.finally() 는 확정된 약속에 추가 작업을 연결하는데 사용된다.
이 함수들은 promise를 반환하며 연쇄적으로 연결할 수 있다.

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("foo");
  }, 300);
});

myPromise
	// myPromise가 완료되면 handleFulfilled*을 실행
	// 실패하면 handleRejected*를 실행
  .then(handleFulfilledA, handleRejectedA)
  .then(handleFulfilledB, handleRejectedB)
  .then(handleFulfilledC, handleRejectedC);

then()에 콜백 함수가 없더라도 처리는 체인의 다음 링크로 계속된다.
따라서 체인은 마지막 catch() 까지 모든 거부 콜백 함수를 안전하게 생략할 수 있다.

각 then() 함수에서 거부된 프라미스를 처리하면 프라미스 체인의 더 아래쪽에 영향을 미친다.

오류를 즉시 처리해야 하기 때문에 선택의 여지가 없는 경우도 있다.
이런 경우 체인 아래로 오류 상태를 유지하기 위해 어떤 유형의 오류를 던져야 한다.

반면에 즉각적인 대응이 필요가 없는 경우 마지막 catch() 함수까지 오류 처리를 생략하는 것이 더 간단하다.

catch() 함수는 실제로는 약속이 이행된 경우에 대한 콜백 함수를 위한 슬롯이 없는 then() 함수에 불과하다.

myPromise
  .then(handleFulfilledA)
  .then(handleFulfilledB)
  .then(handleFulfilledC)
  .catch(handleRejectedAny);
  • arrow function 적용한 모습
myPromise
  .then((value) => `${value} and bar`)
  .then((value) => `${value} and bar again`)
  .then((value) => `${value} and again`)
  .then((value) => `${value} and again`)
  .then((value) => {
    console.log(value);
  })
  .catch((err) => {
    console.error(err);
  });

💡 빠른 실행을 위해 모든 동작을 하나의 핸들러 내에서 수행하는 것이 바람직하다.
그렇지 않으면 모든 핸들러를 순차적으로 실행하는 데 시간이 소요된다.

Promise의 종료 조건에 따라 체인에서 다음 Promise의 확정(settled) 상태가 결정된다.
완료(fulfilled) 상태는 성공적으로 완료되었음을 나타내며, 실패(rejected) 상태는 성공하지 못했음을 나타낸다.
체인의 각 promise 반환 값은 다음 then으로 전달되고 실패 사유는 체인의 다음 reject 핸들러 함수로 전달된다.

0개의 댓글