Promise 동시성 메서드 정리

Dev.Jo·2023년 5월 21일
1

Promise 객체에는 비동기 작업을 동시에 처리하기 위한 동시성 정적 메서드가 있습니다. 아래 정적 메서드를 사용하면 비동기 작업을 다양한 상황에 따라 처리할 수 있습니다.

  • Promise.all()
  • Promise.any()
  • Promise.race()
  • Promise.allSettled()

이번 글에서는 4가지 Promsie 동시성 정적 메서드를 정리합니다.

Promise의 상태

우선 Promise 객체의 세 가지 상태에 대해 얘기하려고합니다.
Promise 객체 상태는 아래 세 가지 중 하나를 가집니다.

  • fulfilled(이행된): 작업이 성공했음을 의미합니다
  • rejected(거부된): 작업이 실패했음을 의미합니다
  • pending(보류): 이행된 상태도 아니고 거부된 상태도 아닌 상태입니다

이행되었거나 거부되었다면settled(결정)되었다고 합니다.

Promise의 초기값은 pending입니다. 아래 그림처럼 작업의 처리 결과에 따라 Promise는 이행된 상태 또는 거부된 상태가 됩니다. 새로운 Promise를 반환하여 chaning됩니다.

https://velog.velcdn.com/images/sa02045/post/987b61d2-5a55-401e-9440-759bff02aa9d/image.png

Promise 동시성 정적 메서드는 다음과 같은 특징을 가집니다.

  • Promise 이터러블 객체를 인자로 받습니다.(배열등)
  • 정적 메서드의 리턴값은 새로운 Promise입니다.
const promise = Promise.all([promise1, promise2]);

Promise.any()

인자로 받은 이터러블 Promise 중에서 가장 먼저 이행된 결과를 얻고 싶을 때 사용합니다.

Promise.any()는 입력 받은 하나의 Promise중 하나라도 이행될때, 가장 첫 번째로 이행된 Promise의 이행된 값을 가집니다.

다음 예제에서 입력 Promise 배열 중 가장 먼저 이행되는 promise2의 값을 가집니다.

const promise1 = Promise.reject("promise1");
const promise2 = new Promise((resolve) => {
  setTimeout(resolve, 100, "promise2")
});
const promise3 = new Promise((resolve) => {
  setTimeout(resolve, 500, "promise3")
});

const promises = [promise1, promise2, promise3];

// 가장 먼저 이행된 promise2
Promise.any(promises).then((value) => console.log(value)); // "promsie2"

아래와 같이 모든 이터러블 Promise가 거부되는 경우 Promise.any() 정적메서드의 반환 Promise도 거부됩니다.

거부될때 AggregateError 에러와 함께 거부된 이유(reason)을 담고있는 errors 프러퍼티 가집니다.


const promise1 = Promise.reject("promise1");
const promise2 = Promise.reject("promise2");
const promise3 = Promise.reject("promise3");

const promises = [promise1, promise2, promise3];

Promise.any(promises).catch((e) => {
  console.log(e instanceof AggregateError); // true
  console.log(e.errors); // [ 'promise1', 'promise2', 'promise3' ]
});

Promise.race()

Promise.race()는 가장 먼저 Settled (이행되었거나 거부)된 Promise의 값을 가지고 싶을 때 사용합니다.

아래 예제에서는 가장 먼저 settled된 promise1의 값을 가집니다. promise1은 거부되었기 때문에 Promise.race()의 반환 Promise의 거부된 값도 promise1을 가집니다

const promise1 = Promise.reject("promise1");
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, "promise2"));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, "promise3"));

const promises = [promise1, promise2, promise3];

Promise.race(promises)
  .catch((e) => {
    console.log(e); // "promise1"
  // 가장 먼저 settled된 promise1
  });

이러한 Promise.race()의 특성을 사용하면 비동기 작업의 타임아웃 기능을 구현할 수 있습니다.

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error('Timeout'));
    }, ms);
  });
}

function fetchData() {
  return new Promise((resolve, reject) => {
  });
}

Promise.race([fetchData(), timeout(5000)])
  .then(result => {
    // 완료된 작업처리
  })
  .catch(error => {
    // 타임아웃
  });

Promise.all()

Promise.all() 정적메서드는 여러 개의 Promise가 모두 이행할 때까지 기다리고 모든 결과를 한꺼번에 얻고 싶을 때 사용합니다.

입력받은 모든 Promise가 이행되어야만 이행되는 Promise를 반환합니다. 만약 하나의 Promise라도 거부된다면 반환 Promise는 거부됩니다. 그외에도 아래와 같은 특징이 있습니다.

  • 입력 Promise들이 모두 settled 될 때 까지 기다립니다. 다시말해 아래 예제에서는 6초가 지나야만 반환 Promise를 얻을 수 있습니다.
  • 이행된 값은 입력 Promise의 이행값이 담긴 배열입니다.
const promise1 = Promise.resolve("promise1");
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, "promise2"));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, "promise3"));

const promises = [promise1, promise2, promise3];

Promise.all(promises)
  .then((value) => {
    console.log(value); // [ 'promise1', 'promise2', 'promise3' ]
  })

만약 단 하나의 Promise라도 거부된다면 Promise.all()의 반환메서드는 거부됩니다.

const promise1 = Promise.reject("promise1");
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, "promise2"));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, "promise3"));

const promises = [promise1, promise2, promise3];

Promise.all(promises)
  .catch((e) => {
    console.log(e); // promise1
  });

Promise.allSettled()

Promise.allSettled() 정적메서드의 반환 Promise의 이행값도 Promise.all()과 같이 배열입니다. 단, 메서드 이름에서 알 수 있듯 입력 Promise들이 이행되었을뿐만 아니라 거부되었을때 이행되는 반환 Promise를 가집니다.

반환값은 status,reason 또는value 프러퍼티를 가지는 객체의 배열입니다.

  • status: Promise의 상태를 나타내는 문자열입니다. 가능한 값은 "fulfilled" (성공), "rejected" (실패)입니다.
  • value: Promise가 이행된 경우 해당 결과 값이 들어있습니다.
  • reason: Promise가 거부된 경우 해당 거부 원인이 들어있습니다.
const promise1 = Promise.reject("promise1");
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, "promise2"));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, "promise3"));

const promises = [promise1, promise2, promise3];

Promise.allSettled(promises).then((value) => {
  console.log(value);
});
  // [
  // { status: 'rejected', reason: 'promise1' },
  // { status: 'fulfilled', value: 'promise2' },
  // { status: 'fulfilled', value: 'promise3' }
  // ]

정리

  • 단 하나의 비동기 작업이라도 실패하면 모든 프로세스를 실패로 간주하고 싶을 때 -> Promise.all()
  • 가장 먼저 성공된 비동기 작업 결과값을 사용하고 싶을 때 -> Promise.any()
  • 타임아웃 처리를 하고 싶을 때 -> Promise.race()
  • 모든 Promise의 이행, 거부 결과를 얻고 싶을 때 -> Promise.allSettled()
profile
소프트웨어 엔지니어, 프론트엔드 개발자

0개의 댓글

관련 채용 정보