본문 바로가기

Lab Notes

promise.all & promise.allsettled 이해하기

Promise.all

Promise.all 메서드는 여러 개의 프로미스를 포함하는 배열을 인자로 받아, 모든 프로미스가 성공적으로 이행(resolve)될 때까지 기다립니다. 모든 프로미스가 성공적으로 이행되면, 각 프로미스의 결과를 모아 배열로 반환합니다.

동작 원리

  • 프로미스 배열을 받아 각각의 프로미스가 이행될 때까지 기다립니다.
  • 모든 프로미스가 성공적으로 이행되면, 각 프로미스의 결과를 모은 배열을 최종 결과로 반환합니다.
  • **하나라도 거부(reject)**되면, Promise.all은 즉시 거부됩니다. 그리고 첫 번째 거부된 프로미스의 에러를 반환합니다.
Promise.all([
  Promise.resolve('A'),
  Promise.resolve('B')
]).then(results => {
  console.log(results); // ['A', 'B']
}).catch(error => {
  console.log(error);
});

이 경우 모든 프로미스가 성공적으로 처리되므로 결과로 ['A', 'B']가 출력됩니다.

Promise.all([
  Promise.resolve('A'),
  Promise.reject('B')
]).then(results => {
  console.log(results); // 이 줄은 실행되지 않습니다.
}).catch(error => {
  console.log(error); // 'B'가 출력됩니다.
});

 

어떻게 동작하는걸까?

In My Opinion!!
프로미스 배열의 각 요소를 순회하면서 각 프로미스의 성공 또는 실패 여부를 처리합니다. 성공한 경우, 아직 어떤 프로미스도 거부되지 않은 상태라면 해당 결과를 배열의 알맞은 인덱스에 저장합니다. 프로미스가 실패할 경우, 거부 상태를 나타내는 플래그를 변경하여 더 이상 성공한 프로미스의 결과를 저장하지 않는 방식으로 구현할 수 있을 것 같습니다.
function simplePromiseAll(promises) {
  return new Promise((resolve, reject) => {
    if (!Array.isArray(promises)) {
      reject(new TypeError("Input must be an array of promises."));
      return;
    }

    const results = new Array(promises.length);
    let completed = 0;
    const total = promises.length;
    let rejected = false; // 거부 발생 여부를 추적하는 플래그

    if (total === 0) {
      resolve(results); // 빈 배열의 경우 즉시 resolve
      return;
    }

    promises.forEach((promise, index) => {
      Promise.resolve(promise).then(value => {
        if (!rejected) { // 거부된 상태가 아닐 때만 결과 처리
          results[index] = value;
          completed++;
          if (completed === total) {
            resolve(results);
          }
        }
      }).catch(error => {
        if (!rejected) { // 아직 거부되지 않았다면
          rejected = true;
          reject(error);
        }
      });
    });
  });
}

// 성공 시나리오
simplePromiseAll([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)])
  .then(result => console.log('Success:', result))
  .catch(error => console.log('Error:', error));

// 실패 시나리오
simplePromiseAll([Promise.resolve(1), Promise.reject('Failure'), Promise.resolve(3)])
  .then(result => console.log('Success:', result))
  .catch(error => console.log('Error:', error));

Promise.allSettled

Promise.allSettled 메서드는 Promise.all과 유사하게 여러 프로미스를 처리하지만, 모든 프로미스의 완료를 기다린 후 각 프로미스의 결과(성공 또는 실패)를 객체로 담은 배열을 반환합니다. 이 메서드는 프로미스가 거부되더라도 다른 프로미스의 결과에 영향을 주지 않습니다.

동작 원리

  • 프로미스 배열을 받아 각 프로미스가 이행되거나 거부될 때까지 기다립니다.
  • 각 프로미스의 결과에 관계없이, 모든 프로미스가 처리될 때까지 기다립니다.
  • 각 프로미스의 최종 상태(성공 또는 실패)와 값을 객체 형태로 반환합니다.
Promise.allSettled([
  Promise.resolve('A'),
  Promise.reject('B')
]).then(results => {
  console.log(results); // [{status: 'fulfilled', value: 'A'}, {status: 'rejected', reason: 'B'}]
});

 

어떻게 동작하는걸까?

In My Opinion!!
프로미스 배열의 각 요소를 순회하면서 각 프로미스가 성공했는지, 실패했는지를 처리합니다. 성공 시에는 결과와 함께 'fulfilled' 상태를, 실패 시에는 오류와 함께 'rejected' 상태를 결과 배열에 저장합니다. 모든 프로미스의 처리가 완료되었는지는 finally메서드를 통해 확인하며, 이를 통해 모든 결과가 저장된 후 배열을 반환하는 방식으로 구현할 수 있을 것 같습니다.
function simplePromiseAllSettled(promises) {
  return new Promise((resolve) => {
    const results = [];
    let completed = 0;
    const total = promises.length;

    if (total === 0) {
      resolve(results);  // 빈 배열을 즉시 resolve
      return;
    }

    promises.forEach((promise, index) => {
      // 프로미스로 변환 (이미 프로미스가 아니라면)
      Promise.resolve(promise)
        .then(value => {
          // 성공한 경우, 상태와 값을 결과 배열에 저장
          results[index] = { status: 'fulfilled', value: value };
        })
        .catch(reason => {
          // 실패한 경우, 상태와 이유를 결과 배열에 저장
          results[index] = { status: 'rejected', reason: reason };
        })
        .finally(() => {
          completed += 1;
          if (completed === total) {
            // 모든 프로미스가 처리되면 결과 배열을 resolve
            resolve(results);
          }
        });
    });
  });
}

// 성공 및 실패가 섞인 시나리오
simplePromiseAllSettled([Promise.resolve(1), Promise.reject('Failure'), Promise.resolve(3)])
  .then(result => console.log('Results:', result))
  .catch(error => console.log('Error:', error));  // allSettled은 실패 시 catch 블록을 실행하지 않습니다.

// 모두 성공 시나리오
simplePromiseAllSettled([Promise.resolve('A'), Promise.resolve('B')])
  .then(result => console.log('Results:', result));

 

 

'Lab Notes' 카테고리의 다른 글

setTimeout의 정확성  (0) 2024.04.09
BigInt vs Number  (0) 2023.11.10
HTML vs XML  (0) 2023.11.09