[javascript] Promise 메서드 비교 (all, allSettled, any, race)

insung·2025년 4월 16일

JavaScript Promise에는 여러 개의 Promise를 다루는 데 유용한 몇 가지 정적 메서드가 있음.
대표적으로

  • Promise.all, Promise.allSettled, Promise.any, Promise.race가 있으며 각각 다른 방식으로 Promise 배열을 처리.

1. Promise.all()

  • Promise.all() 메서드는 주어진 Promise 배열의 모든 Promise가 성공적으로 처리될 때까지 기다림.

동작 방식:

  • 입력으로 Promise 배열을 받음.
  • 배열의 모든 Promise가 이행되면, 이행된 값들을 배열로 묶어 반환하는 새로운 Promise를 반환.
  • 하나라도 거부된 Promise가 있으면, 즉시 전체 Promise가 거부.

const promise1 = Promise.resolve(1);
const promise2 = new Promise((resolve) => setTimeout(resolve, 200, 2));
const promise3 = new Promise((resolve) => setTimeout(resolve, 100, 3));

Promise.all([promise1, promise2, promise3])
  .then((values) => {
    console.log(values); // [1, 2, 3]
  })
  .catch((error) => {
    console.error(error); // 처리되지 않음
  });

const promise4 = Promise.resolve(1);
const promise5 = Promise.reject('Error');
const promise6 = Promise.resolve(3);

Promise.all([promise4, promise5, promise6])
  .then((values) => {
    console.log(values); // 처리되지 않음
  })
  .catch((error) => {
    console.error(error); // Error
  });

활용: 여러 비동기 작업의 결과가 모두 필요한 경우에 유용.
예를 들어, 여러 API 호출을 병렬로 실행하고 모든 응답을 처리해야 할 때 사용할 수 있음

2. Promise.allSettled()

  • Promise.allSettled() 메서드는 주어진 Promise 배열의 모든 Promise가 처리될 때까지 기다립니다 (이행되거나 거부되거나).

동작 방식:

  • 입력으로 Promise 배열을 받음
  • 배열의 모든 Promise가 처리되면, 각 Promise의 결과(이행 값 또는 거부 사유)를 담은 배열을 반환하는 새로운 Promise를 반환
  • Promise의 처리 결과는 { status: 'fulfilled', value: value } 또는 { status: 'rejected', reason: reason } 형태의 객체로 반환
const promise1 = Promise.resolve(1);
const promise2 = Promise.reject('Error');
const promise3 = new Promise((resolve) => setTimeout(resolve, 100, 3));

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

활용: 모든 비동기 작업의 결과를 알아야 할 때 유용.
예를 들어, 여러 API 호출의 성공 여부와 관계없이 모든 응답을 처리해야 할 때 사용할 수 있음

3. Promise.any()

  • Promise.any() 메서드는 주어진 Promise 배열에서 가장 먼저 이행되는 Promise를 기다림

동작 방식:

  • 입력으로 Promise 배열을 받음
  • 배열의 Promise 중 하나라도 이행되면, 그 이행된 값을 반환하는 새로운 Promise를 반환
  • 모든 Promise가 거부되면, AggregateError를 발생시킴
const promise1 = Promise.reject('Error1');
const promise2 = new Promise((resolve) => setTimeout(resolve, 200, 2));
const promise3 = Promise.reject('Error3');

Promise.any([promise1, promise2, promise3])
  .then((value) => {
    console.log(value); // 2
  })
  .catch((error) => {
    console.error(error); // 처리되지 않음
  });

const promise4 = Promise.reject('Error1');
const promise5 = Promise.reject('Error2');

Promise.any([promise4, promise5])
  .then((value) => {
    console.log(value); // 처리되지 않음
  })
  .catch((error) => {
    console.error(error); // AggregateError: All promises were rejected
  });

활용: 여러 Promise 중 가장 빠른 응답이 필요한 경우에 유용.
예를 들어, 여러 서버에 동일한 요청을 보내고 가장 먼저 응답하는 서버의 결과를 사용하고 싶을 때 사용할 수 있음

4. Promise.race()

  • Promise.race() 메서드는 주어진 Promise 배열에서 가장 먼저 처리되는 Promise를 기다림 (이행되거나 거부되거나).

동작 방식:

  • 입력으로 Promise 배열을 받음.
  • 배열의 Promise 중 가장 먼저 처리되는 Promise의 값(이행 값 또는 거부 사유)을 반환하는 새로운 Promise를 반환.
const promise1 = new Promise((resolve) => setTimeout(resolve, 500, 1));
const promise2 = Promise.reject('Error');
const promise3 = new Promise((resolve) => setTimeout(resolve, 100, 3));

Promise.race([promise1, promise2, promise3])
  .then((value) => {
    console.log(value); // 3
  })
  .catch((error) => {
    console.error(error); // 처리되지 않음
  });

const promise4 = new Promise((resolve) => setTimeout(resolve, 500, 1));
const promise5 = Promise.reject('Error');

Promise.race([promise4, promise5])
  .then((value) => {
    console.log(value); // 처리되지 않음
  })
  .catch((error) => {
    console.error(error); // Error
  });

활용:
Promise 중 가장 빠른 결과가 필요한 경우에 유용.
예를 들어, 타임아웃을 구현하거나, 여러 작업 중 가장 먼저 완료되는 작업을 처리해야 할 때 사용할 수 있음.

5. with Tanstack Query

  • TanStack Query는 비동기 데이터를 관리하는 강력한 라이브러리이며, Promise 기반으로 작동.
  • 따라서 Promise.all, Promise.allSettled, Promise.any, Promise.race와 함께 사용하여 여러 관련 쿼리를 효율적으로 처리할 수 있음.

Promise.all()과 함께 사용

  • 여러 TanStack Query 쿼리를 병렬로 실행하고 모든 쿼리가 성공적으로 완료된 후에 결과를 처리해야 하는 경우에 Promise.all()을 사용할 수 있음.
import { useQuery } from '@tanstack/react-query';

const query1 = useQuery({ queryKey: ['data1'], queryFn: () => fetchData1() });
const query2 = useQuery({ queryKey: ['data2'], queryFn: () => fetchData2() });
const query3 = useQuery({ queryKey: ['data3'], queryFn: () => fetchData3() });

// Promise.all을 사용하여 모든 쿼리가 완료될 때까지 기다립니다.
Promise.all([query1.fetch(), query2.fetch(), query3.fetch()])
  .then(([data1, data2, data3]) => {
    // 모든 데이터가 준비되었습니다. 이제 UI를 업데이트하거나 다른 작업을 수행할 수 있습니다.
    console.log(data1, data2, data3);
  })
  .catch((error) => {
    // 쿼리 중 하나라도 실패한 경우 처리합니다.
    console.error(error);
  });

Promise.allSettled()와 함께 사용

  • 여러 TanStack Query 쿼리의 결과를 개별적으로 처리해야 하는 경우에 Promise.allSettled()를 사용할 수 있음.
  • 각 쿼리의 성공 여부와 관계없이 모든 쿼리의 결과를 얻을 수 있음.
import { useQuery } from '@tanstack/react-query';

const query1 = useQuery({ queryKey: ['data1'], queryFn: () => fetchData1() });
const query2 = useQuery({ queryKey: ['data2'], queryFn: () => fetchData2() });
const query3 = useQuery({ queryKey: ['data3'], queryFn: () => fetchData3() });

Promise.allSettled([query1.fetch(), query2.fetch(), query3.fetch()])
  .then((results) => {
    results.forEach((result) => {
      if (result.status === 'fulfilled') {
        console.log(result.value); // 성공한 쿼리 결과 처리
      } else {
        console.error(result.reason); // 실패한 쿼리 오류 처리
      }
    });
  });

Promise.any()와 함께 사용

  • 여러 TanStack Query 쿼리 중 하나라도 성공하면 결과를 사용하고 싶을 경우에 Promise.any()를 사용할 수 있음.
  • 이는 중복된 데이터 소스에 쿼리를 보내고 가장 빠른 응답을 사용하는 경우에 유용할 수 있음.
import { useQuery } from '@tanstack/react-query';

const query1 = useQuery({ queryKey: ['data1'], queryFn: () => fetchDataFromSource1() });
const query2 = useQuery({ queryKey: ['data2'], queryFn: () => fetchDataFromSource2() });

Promise.any([query1.fetch(), query2.fetch()])
  .then((data) => {
    // 첫 번째로 성공한 쿼리 결과를 사용합니다.
    console.log(data);
  })
  .catch((error) => {
    // 모든 쿼리가 실패한 경우 처리합니다.
    console.error(error);
  });

Promise.race()와 함께 사용

  • TanStack Query 쿼리에 대한 타임아웃을 설정하거나, 가장 먼저 완료되는 쿼리의 결과를 사용해야 하는 경우에 Promise.race()를 사용할 수 있음.
import { useQuery } from '@tanstack/react-query';

const query = useQuery({
  queryKey: ['data'],
  queryFn: () => {
    const fetchPromise = fetchData();
    const timeoutPromise = new Promise((_, reject) =>
      setTimeout(() => reject(new Error('Timeout')), 5000) // 5초 타임아웃
    );
    return Promise.race([fetchPromise, timeoutPromise]);
  },
});

if (query.isLoading) {
  return <div>Loading...</div>;
}

if (query.isError) {
  return <div>Error: {query.error.message}</div>;
}

return <div>Data: {query.data}</div>;
profile
안녕하세요 프론트엔드 관련 포스팅을 주로 하고 있습니다

0개의 댓글