상세 컨텐츠

본문 제목

javascript.info - 프라미스와 async, await(2)

개발공부/개발공부

by Dal_pang 2023. 1. 2. 15:16

본문

 [ 프라미스 API ]

Promise 클래스의 5가지 정적 메서드, 이중 Promise.all을 가장 많이 사용한다.

 

  • Promise.all : 여러 프라미스가 모두 준비될 때까지 기다릴 때 사용. '모 아니면 도' 형식.
let promise = Promise.all([...promises...]);
//---사용예---
Promise.all([
  new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
  new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
  new Promise(resolve => setTimeout(() => resolve(3), 1000))  // 3
]).then(alert); // 프라미스 전체가 처리되면 1, 2, 3이 반환됩니다. 각 프라미스는 배열을 구성하는 요소가 됩니다.

 

==> 배열 또는 이터러블 객체를 요소로 받아 새로운 프라미스 리턴함. (일반 값도 요소로 넘기기 가능)

Promise.all에 전달되는 프라미스 중 하나라도 거부되면 Promise.all이 반환하는 프라미스는 에러와 함께 바로 거부(REJECT)됨.

(하나라도 거부되는 순간 바로 Promise.all이 거부되므로 배열에 저장된 다른 프라미스의 결과는 완전 무시됨, 이행된 결과도 무시)

 

  • Promise.allSettled

최근 스펙에 추가된 문법. Promise.all과 달리 모든 프라미스가 처리될 때까지 기다림.

여러 요청 중 하나가 실패하더라도 다른 요청 결과가 필요할때 사용하며, 각 프라미스의 상태와 값 또는 에러를 받음.

> 응답이 성공할 경우 – {status:"fulfilled", value:result}
> 에러가 발생한 경우 – {status:"rejected", reason:error}

 

  • Promise.race

Promise.race, Promise.all과 비슷하나, 가장 먼저 처리되는 프라미스의 결과(혹은 에러)를 반환.

문법:

let promise = Promise.race(iterable);
Promise.race([
  new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
  new Promise((resolve, reject) => setTimeout(() => reject(new Error("에러 발생!")), 2000)),
  new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).then(alert); // 1

가장 빨리 처리상태가 되는 첫번째 프라미스의 결과만 리턴되고, 나머지는 무시됨.

 

  • Promise.resolve, Promise.reject

async/await이 생긴 후 잘 사용되지 않음.

- Promise.resolve : Promise.resolve(value)는 결괏값이 value인 이행 상태 프라미스를 생성.

- Promise.reject : Promise.reject(error)는 결괏값이 error인 거부 상태 프라미스 생성.

 


[ 프라미스화 Promisification ]

'프라미스화(Promisification)' : 콜백을 받는 함수 -> 프라미스 반환 함수로 바꾸는 것.

 - async/await과 함께 프라미스화 해서 사용하는것 권장. But, 콜백을 완전 대체하지는 못함.

프라미스는 하나의 결과만 가질 수 있지만, 콜백은 여러번 호출할 수 있기 때문.

프라미스화는 콜백을 단 한 번 호출하는 함수에만 적용할것. 프라미스 화한 함수의 콜백은 여러 번 호출해도 두 번째부터는 무시됨.

 


[ 마이크로태스크 ]

모든 프라미스 동작은 '마이크로태스크 큐'라는 내부 Promise Job 큐에 들어가서 처리되어 프라미스 핸들링은 항상 비동기처리.

.then/catch/finally 핸들러는 항상 현재 코드가 종료되고 난 후에 호출된다.

let promise = Promise.resolve();

promise.then(() => alert("프라미스 성공!"));

alert("코드 종료"); // 얼럿 창이 가장 먼저 뜹니다.
//코드종료 알러트가 먼저 뜨고, 그 다음 프라미스 성공 알러트가 뜨게된다.

만약 .then/catch/finally 호출 이후에 실행할 코드가 있다면,

.then을 체인에 추가하여 그 안에 작성할 것.

Promise.resolve()
  .then(() => alert("프라미스 성공!"))
  .then(() => alert("코드 종료"));

 

처리되지 못한 거부 unhandledrejection

마이크로태스크 큐 끝에서 프라미스 에러가 처리되지 못할 때 발생.

이를 대비해 프라미스 체인에 .catch 추가해 에러 처리.

만약, 개발자가 .catch를 추가하지 않은 경우, 엔진은 마이크로태스크 큐가 빈 이후 unhandledrejection 이벤트를 트리거.

 

let promise = Promise.reject(new Error("프라미스 실패!"));
setTimeout(() => promise.catch(err => alert('잡았다!')), 1000);

// Error: 프라미스 실패!
window.addEventListener('unhandledrejection', event => alert(event.reason));

위의 경우, catch를 늦게 실행해 마이크로태스크 큐 내부 작업을 모두 완료한 후 unhandledrejection이 생성됨.

때문에, "프라미스 실패!'가 먼저 출력된 후에 '잡았다!'가 출력된다.

 

 

728x90

관련글 더보기