0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptの非同期処理を学ぶ ― Promise.all / race / allSettled / any

0
Last updated at Posted at 2026-09-05

はじめに

JavaScriptの非同期処理について学ぶため、今回は複数のPromiseを扱う以下の4つのメソッドを実際に動かしてみます。

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

いずれも複数のPromiseをまとめて扱うためのメソッドですが、
「いつ処理全体がsettledになるのか」「rejectをどう扱うのか」がそれぞれ異なります。
今回は書籍検索を題材にし、検索処理に意図的な遅延を設定して、それぞれの挙動を確認します。

実験に使用するデータ

const books = {
    "9784480096432": {
        isbn: "9784480096432",
        title: "物と心",
        author: "大森 荘蔵"
    },
    "9784782800157": {
        isbn: "9784782800157",
        title: "流れとよどみ",
        author: "大森 荘蔵"
    },
    "9784065249444": {
        isbn: "9784065249444",
        title: "新視覚新論",
        author: "大森 荘蔵"
    },
    "9784782800225": {
        isbn: "9784782800225",
        title: "名指しと必然性",
        author: "Saul Kripke"
    },
    "9784582770124": {
        isbn: "9784582770124",
        title: "指示と存在",
        author: "Saul Kripke"
    }
};

const authors = {
    "大森 荘蔵": {
        name: "大森 荘蔵",
        majorWorks: ["9784480096432", "9784782800157", "9784065249444"]
    },
    "Saul Kripke": {
        name: "Saul Kripke",
        majorWorks: ["9784782800225", "9784582770124"]
    }
};

共通で使用する関数

/**
 * ISBNから書籍を検索する。
 *
 * @param {string} isbn ISBN
 * @param {number} delay 遅延時間(ミリ秒)
 * @returns {Promise<object>}
 */
function findBook(isbn, delay) {
    return new Promise((resolve, reject) => {
        console.log(
            `書籍検索開始: ${isbn}${delay}ms)`
        );

        setTimeout(() => {
            const book = books[isbn];

            if (book === undefined) {
                reject(
                    new Error(`書籍が見つかりません: ${isbn}`)
                );
                return;
            }

            console.log(
                `書籍検索完了: ${book.title}${delay}ms)`
            );

            resolve(book);
        }, delay);
    });
}

存在しないISBNを指定するとPromiseをrejectします。
今回は実際の通信処理を行うのではなく、setTimeout()によって時間のかかる非同期処理を再現しています。

Promise.all()

サンプルコード

async function processWithPromiseAll() {
    console.log("=== Promise.all() 開始 ===");

    try {
        const results = await Promise.all([
            findBook("9784480096432", 3000),
            findBook("9784782800157", 1000),
            findBook("9784065249444", 2000)
        ]);

        console.log("すべての検索が完了しました。");

        results.forEach((book) => {
            console.log(
                `- ${book.title} / ${book.author}`
            );
        });

    } catch (error) {
        console.error("エラー:", error.message);
    }
}

processWithPromiseAll();

概要・仕様

Promise.all()は、渡されたPromiseがすべてfulfilledになるまで待ちます
すべて成功すると、それぞれのPromiseの結果を配列として取得できます。
1つでもrejectすると、Promise.all()もrejectします。
また、結果の配列はPromiseが完了した順番ではなく、Promise.all()に渡した順番になります。
今回の例では、検索処理は1000ms、2000ms、3000msの順に完了しますが、結果の配列は指定した順番になります。

実行結果

=== Promise.all() 開始 ===
書籍検索開始: 9784480096432(3000ms)
書籍検索開始: 9784782800157(1000ms)
書籍検索開始: 9784065249444(2000ms)
書籍検索完了: 流れとよどみ(1000ms)
書籍検索完了: 新視覚新論(2000ms)
書籍検索完了: 物と心(3000ms)
すべての検索が完了しました。
- 物と心 / 大森 荘蔵
- 流れとよどみ / 大森 荘蔵
- 新視覚新論 / 大森 荘蔵

Promise.allSettled()

サンプルコード

async function processWithPromiseAllSettled() {
    console.log("=== Promise.allSettled() 開始 ===");

    const results = await Promise.allSettled([
        findBook("9784480096432", 3000),
        findBook("存在しないISBN", 1000),
        findBook("9784065249444", 2000)
    ]);

    console.log("すべての検索が終了しました。");

    results.forEach((result, index) => {

        if (result.status === "fulfilled") {
            console.log(
                `${index + 1}: 成功 - ${result.value.title}`
            );
        } else {
            console.log(
                `${index + 1}: 失敗 - ${result.reason.message}`
            );
        }
    });
}

processWithPromiseAllSettled();

概要・仕様

Promise.allSettled()は、複数のPromiseがすべてsettledになるまで待ちます
Promise.all()と異なり、途中でrejectしても処理全体がrejectされることはありません。
各Promiseについて、成功・失敗の両方を結果として取得できます。
成功した場合は、

{
    status: "fulfilled",
    value: ...
}

失敗した場合は、

{
    status: "rejected",
    reason: ...
}

という結果になります。
今回の例では、存在しないISBNを1つ含めているため、成功した検索と失敗した検索の両方を確認できます。
結果の配列は、Promiseがsettledになった順番ではなく、
Promise.allSettled()に渡した順番になります。

実行結果

=== Promise.allSettled() 開始 ===
書籍検索開始: 9784480096432(3000ms)
書籍検索開始: 存在しないISBN(1000ms)
書籍検索開始: 9784065249444(2000ms)
書籍検索完了: 新視覚新論(2000ms)
書籍検索完了: 物と心(3000ms)
すべての検索が終了しました。
1: 成功 - 物と心
2: 失敗 - 書籍が見つかりません: 存在しないISBN
3: 成功 - 新視覚新論

Promise.race()

サンプルコード

async function processWithPromiseRace() {
    console.log("=== Promise.race() 開始 ===");

    try {
        const result = await Promise.race([
            findBook("9784480096432", 3000),
            findBook("9784782800157", 1000),
            findBook("9784065249444", 2000)
        ]);

        console.log("最初に結果が確定した検索:");

        console.log(
            `- ${result.title} / ${result.author}`
        );

    } catch (error) {
        console.error("エラー:", error.message);
    }
}

processWithPromiseRace();

概要・仕様

Promise.race()は、複数のPromiseのうち、最初にsettledになったPromiseの結果を採用します
settledとは、Promiseが以下のいずれかになった状態です。

  • fulfilled
  • rejected

つまり、「最初に成功したPromise」ではありません。
最初にfulfilledになった場合はfulfilledになり、最初にrejectedになった場合はrejectedになります。
今回の例では、1000msの検索が最初に完了するため、その結果が返されます。
なお、Promise.race()で結果が決まったからといって、他のPromiseが自動的にキャンセルされるわけではありません。

実行結果

=== Promise.race() 開始 ===
書籍検索開始: 9784480096432(3000ms)
書籍検索開始: 9784782800157(1000ms)
書籍検索開始: 9784065249444(2000ms)
書籍検索完了: 流れとよどみ(1000ms)
最初に結果が確定した検索:
- 流れとよどみ / 大森 荘蔵
書籍検索完了: 新視覚新論(2000ms)
書籍検索完了: 物と心(3000ms)

Promise.any()

サンプルコード

async function processWithPromiseAny() {
    console.log("=== Promise.any() 開始 ===");

    try {
        const result = await Promise.any([
            findBook("9784480096432", 3000),
            findBook("9784782800157", 1000),
            findBook("9784065249444", 2000)
        ]);

        console.log("最初に成功した検索:");

        console.log(
            `- ${result.title} / ${result.author}`
        );

    } catch (error) {
        console.error("エラー:", error);
    }
}

processWithPromiseAny();

概要・仕様

Promise.any()は、複数のPromiseのうち、最初にfulfilledになったPromiseの結果を採用します
Promise.race()と似ていますが、重要な違いがあります。
Promise.race()は、最初にsettledになったPromiseを採用します。
一方、Promise.any()は、最初にfulfilledになったPromiseを採用します。
そのため、最初にrejectしたPromiseがあっても、その時点では処理を終了しません。
すべてのPromiseがrejectした場合には、Promise.any()もrejectします。
この場合、rejectの理由にはAggregateErrorが使用され、
各Promiseがrejectした理由はerror.errorsで取得できます。

実行結果

=== Promise.any() 開始 ===
書籍検索開始: 9784480096432(3000ms)
書籍検索開始: 9784782800157(1000ms)
書籍検索開始: 9784065249444(2000ms)
書籍検索完了: 流れとよどみ(1000ms)
最初に成功した検索:
- 流れとよどみ / 大森 荘蔵
書籍検索完了: 新視覚新論(2000ms)
書籍検索完了: 物と心(3000ms)

4つのメソッドの比較

メソッド 待つ条件 rejectの扱い
Promise.all() すべてfulfilled 1つでもrejectするとreject
Promise.allSettled() すべてsettled 成功・失敗の両方を結果として取得
Promise.race() 最初にsettled 最初がrejectならreject
Promise.any() 最初にfulfilled rejectは無視し、すべてrejectしたらreject

特にPromise.race()Promise.any()は混同しやすいので注意が必要です。

Promise.race()
    ↓
最初にsettledしたPromise
    ↓
fulfilledでもrejectedでもよい

Promise.any()
    ↓
最初にfulfilledしたPromise
    ↓
rejectedは無視

まとめ

今回は、複数のPromiseを扱う4つのメソッドを実際に動かしました。

  • Promise.all()は、すべてのPromiseがfulfilledになるまで待つ
  • Promise.allSettled()は、すべてのPromiseがsettledになるまで待ち、成功・失敗の両方を取得する
  • Promise.race()は、最初にsettledになったPromiseを採用する
  • Promise.any()は、最初にfulfilledになったPromiseを採用する

4つは名前が似ていますが、「何を待つのか」「rejectをどう扱うのか」に注目すると、それぞれの違いを整理できます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?