Promise.allSettledの使い方と活用場面

2024-04-19
--

なぜ使うのか

複数のAPIコールを行い、すべてが完了した後にそれぞれが正常に完了したかどうかの状態とともにレスポンスを返したい場合があります。

Promise.allSettledの仕組み

  • Promiseの配列を受け取ります
  • オブジェクトの配列に解決されるPromiseを返します
  • 各オブジェクトはそれぞれのPromiseの結果を表し、「fulfilled」のステータスと値、または「rejected」のステータスと理由を含みます
  • なぜPromise.allSettledを使うのか?

    Promise.allSettledは、成功・失敗に関わらず複数の非同期処理がすべて完了するのを待つ必要がある場合に特に有用です。例えば:

  • 複数のAPIコールの結果を集約する場合
  • 個々の失敗がプロセス全体を止めるべきでない並列処理を行う場合
  • 一部が失敗しても全体の結果がまだ有用な、さまざまなソースからデータを収集する場合
  • 使用例

    APIコールの集約

    type ApiResponse = { data: any };
    
    const fetchApi1 = (): Promise<ApiResponse> => {
      return new Promise((resolve, reject) => {
        // Simulate API call
        setTimeout(() => resolve({ data: 'API 1 response' }), 1000);
      });
    };
    
    const fetchApi2 = (): Promise<ApiResponse> => {
      return new Promise((resolve, reject) => {
        // Simulate API call
        setTimeout(() => reject(new Error('API 2 failed')), 1500);
      });
    };
    
    const fetchApi3 = (): Promise<ApiResponse> => {
      return new Promise((resolve, reject) => {
        // Simulate API call
        setTimeout(() => resolve({ data: 'API 3 response' }), 2000);
      });
    };
    
    const fetchAllApis = async () => {
      const results = await Promise.allSettled([fetchApi1(), fetchApi2(), fetchApi3()]);
    
      results.forEach((result, index) => {
        if (result.status === 'fulfilled') {
          console.log(`API ${index + 1} succeeded with response:`, result.value);
        } else {
          console.log(`API ${index + 1} failed with reason:`, result.reason);
        }
      });
    };
    
    fetchAllApis();

    複数ファイルアップロードの処理

    type UploadResult = { filename: string; url: string };
    
    const uploadFile = (file: File): Promise<UploadResult> => {
      return new Promise((resolve, reject) => {
        // Simulate file upload
        const isSuccess = Math.random() > 0.5; // Random success or failure
        setTimeout(() => {
          if (isSuccess) {
            resolve({ filename: file.name, url: `https://example.com/${file.name}` });
          } else {
            reject(new Error(`Failed to upload ${file.name}`));
          }
        }, 1000);
      });
    };
    
    const uploadFiles = async (files: File[]) => {
      const results = await Promise.allSettled(files.map(uploadFile));
    
      results.forEach((result, index) => {
        if (result.status === 'fulfilled') {
          console.log(`File ${files[index].name} uploaded successfully:`, result.value);
        } else {
          console.error(`File ${files[index].name} failed to upload:`, result.reason);
        }
      });
    };
    
    // Example usage
    const files: File[] = [
      new File(['content'], 'file1.txt'),
      new File(['content'], 'file2.txt'),
      new File(['content'], 'file3.txt')
    ];
    
    uploadFiles(files);