Skip to content
📚 3 min read

Promise.allSettled Examples ​

Learn how to use Promise.allSettled for handling multiple promises regardless of their outcome.

Basic Usage ​

typescript
// Basic usage with mixed results
async function fetchMultipleUrlsSafely(urls: string[]) {
  const results = await Promise.allSettled(urls.map((url) => fetch(url)));

  return results.map((result, index) => ({
    url: urls[index],
    status: result.status,
    value: result.status === 'fulfilled' ? result.value : undefined,
    error: result.status === 'rejected' ? result.reason : undefined,
  }));
}

// Processing with status tracking
async function processItemsWithStatus<T, R>(
  items: T[],
  processor: (item: T) => Promise<R>
) {
  const results = await Promise.allSettled(items.map(processor));

  return {
    successful: results
      .filter((r): r is PromiseFulfilledResult<R> => r.status === 'fulfilled')
      .map((r) => r.value),
    failed: results
      .filter((r): r is PromiseRejectedResult => r.status === 'rejected')
      .map((r) => r.reason),
  };
}

Advanced Patterns ​

Batch Processing with Results Analysis ​

typescript
interface ProcessingResult<T, R> {
  successful: { input: T; output: R }[];
  failed: { input: T; error: Error }[];
  summary: {
    total: number;
    successCount: number;
    failureCount: number;
    successRate: number;
  };
}

async function processBatchWithAnalysis<T, R>(
  items: T[],
  processor: (item: T) => Promise<R>
): Promise<ProcessingResult<T, R>> {
  const results = await Promise.allSettled(
    items.map((item) => processor(item))
  );

  const successful: { input: T; output: R }[] = [];
  const failed: { input: T; error: Error }[] = [];

  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      successful.push({
        input: items[index],
        output: result.value,
      });
    } else {
      failed.push({
        input: items[index],
        error: result.reason,
      });
    }
  });

  const total = items.length;
  const successCount = successful.length;
  const failureCount = failed.length;

  return {
    successful,
    failed,
    summary: {
      total,
      successCount,
      failureCount,
      successRate: successCount / total,
    },
  };
}

Retry Failed Operations ​

typescript
async function retryFailedOperations<T, R>(
  items: T[],
  processor: (item: T) => Promise<R>,
  maxRetries: number = 3
): Promise<R[]> {
  let currentItems = [...items];
  const results: R[] = new Array(items.length);
  const itemIndices = new Map(items.map((item, index) => [item, index]));

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    if (currentItems.length === 0) break;

    const attemptResults = await Promise.allSettled(
      currentItems.map((item) => processor(item))
    );

    // Process results and collect failed items for retry
    const failedItems: T[] = [];

    attemptResults.forEach((result, index) => {
      const originalIndex = itemIndices.get(currentItems[index])!;

      if (result.status === 'fulfilled') {
        results[originalIndex] = result.value;
      } else {
        if (attempt < maxRetries - 1) {
          failedItems.push(currentItems[index]);
        } else {
          throw new Error(
            `Failed to process item after ${maxRetries} attempts`
          );
        }
      }
    });

    currentItems = failedItems;

    if (failedItems.length > 0 && attempt < maxRetries - 1) {
      // Exponential backoff before retry
      await new Promise((resolve) =>
        setTimeout(resolve, Math.pow(2, attempt) * 1000)
      );
    }
  }

  return results;
}

Progress Tracking ​

typescript
interface ProgressUpdate<T> {
  completed: number;
  total: number;
  successful: T[];
  failed: Error[];
  percentage: number;
}

async function processWithProgress<T, R>(
  items: T[],
  processor: (item: T) => Promise<R>,
  onProgress: (progress: ProgressUpdate<R>) => void
): Promise<{ successful: R[]; failed: Error[] }> {
  const results = await Promise.allSettled(
    items.map(async (item, index) => {
      const result = await processor(item);

      const successful = results
        .slice(0, index + 1)
        .filter((r): r is PromiseFulfilledResult<R> => r.status === 'fulfilled')
        .map((r) => r.value);

      const failed = results
        .slice(0, index + 1)
        .filter((r): r is PromiseRejectedResult => r.status === 'rejected')
        .map((r) => r.reason);

      onProgress({
        completed: index + 1,
        total: items.length,
        successful,
        failed,
        percentage: ((index + 1) / items.length) * 100,
      });

      return result;
    })
  );

  return {
    successful: results
      .filter((r): r is PromiseFulfilledResult<R> => r.status === 'fulfilled')
      .map((r) => r.value),
    failed: results
      .filter((r): r is PromiseRejectedResult => r.status === 'rejected')
      .map((r) => r.reason),
  };
}