Promise.any を一言でいうと
Promise.any は、
「複数の Promise のうち、“最初に成功したもの 1 つ” だけの結果を採用する関数」 です。
race が「一番早く 成功でも失敗でも 決着したやつの結果」を採用するのに対して、any は 「失敗は無視して、とにかく最初に成功したやつを採用する」 という性格を持っています。
ここが重要です。Promise.race = 「最初に決着したやつ(成功 or 失敗)」Promise.any = 「最初に成功したやつ。全員失敗したらまとめてエラー」
とイメージすると区別しやすくなります。
Promise.any の基本的な動き
どう呼ぶか(シグネチャ)
形は他の Promise 系関数と同じです。
Promise.any([promise1, promise2, promise3])
.then((value) => {
// 最初に「成功」した Promise の値
})
.catch((error) => {
// 全部「失敗」した場合だけここに来る
});
JavaScript挙動をまとめると、
複数の Promise を一斉にスタート
成功したものが出てくるまで待つ
最初に成功した Promise の値を then に渡す
もし全ての Promise が失敗したら、catch に「複数失敗をまとめたエラー」が渡る
という流れになります。
いちばんシンプルな例
const p1 = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("p1 失敗")), 300);
});
const p2 = new Promise((resolve) => {
setTimeout(() => resolve("p2 成功"), 500);
});
const p3 = new Promise((resolve) => {
setTimeout(() => resolve("p3 成功"), 800);
});
Promise.any([p1, p2, p3])
.then((value) => {
console.log("最初に成功した値:", value); // "p2 成功"
})
.catch((err) => {
console.error("全部失敗:", err);
});
JavaScript流れを言葉で追うと、
p1 → 300ms 後に失敗
p2 → 500ms 後に成功
p3 → 800ms 後に成功
any は「失敗はスルーして良い、最初に成功したやつが欲しい」ので、
300ms の p1 は無視され、
500ms の p2 が「最初の成功」として採用されます。p3 は、その後で成功しますが、すでに any の結果は決まっているので使われません。
ここが重要です。Promise.any は「失敗を弾いて、最初に成功したやつだけを取るフィルター」
とイメージしておくとよいです。
Promise.race / Promise.all と比べてみる
race との違い(失敗が勝者になるかどうか)
Promise.race の場合は、「最初に成功 or 失敗したやつ」が勝ちです。
const ok = new Promise((resolve) => {
setTimeout(() => resolve("OK"), 1000);
});
const failFast = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("速いエラー")), 300);
});
Promise.race([ok, failFast])
.then((v) => console.log("race 成功:", v))
.catch((e) => console.log("race 失敗:", e.message));
JavaScriptこの例では、300ms の failFast が「最初に決着」するので、race 全体は reject(失敗)になり、catch に来ます。
これを any に変えるとどうなるか。
Promise.any([ok, failFast])
.then((v) => console.log("any 成功:", v))
.catch((e) => console.log("any 失敗:", e));
JavaScript流れはこうです。
300ms:failFast が失敗 → any は「失敗なのでスルー」
1000ms:ok が成功 → any が「これが最初の成功!」として採用、then に “OK” が渡る
つまり同じ 2 つの Promise でも、
race → 速い失敗が勝って、全体がエラー
any → 失敗は無視して、後から来た成功を採用
という違いが出ます。
all と any の方向性の違い
Promise.all は、「全部成功してくれないと困る」状況向きです。
全部成功 → then に [全部の結果]
1つでも失敗 → 即 catch
Promise.any は、「全部成功してほしいわけじゃない、どれか 1 つでも成功してくれればいい」状況向きです。
1つでも成功 → その最初の成功を then へ
全部失敗 → catch
ここが重要です。
all = 「全員合格してほしい試験」
any = 「誰か 1 人でも合格者が出れば OK な試験」
race = 「誰でもいいから最初にゴールした人を採用」
というイメージで覚えておくと、使い分けが直感的になります。
全部失敗したときのエラー(AggregateError)
1つでも成功すれば then、全員失敗なら catch
Promise.any が catch に来るのは、
「配列に渡した Promise が、全部 reject されたときだけ」 です。
const p1 = Promise.reject(new Error("p1 失敗"));
const p2 = Promise.reject(new Error("p2 失敗"));
Promise.any([p1, p2])
.then((value) => {
console.log("成功:", value); // ここには来ない
})
.catch((err) => {
console.log("全部失敗したときのエラー:", err);
});
JavaScriptここで err として渡ってくるのは AggregateError という特殊なエラーオブジェクトです。
ざっくり言うと、
「中に複数のエラーをまとめて持てるエラー」です。
AggregateError の中身をサッと見る
ブラウザや環境によりますが、だいたいこんなイメージです。
Promise.any([
Promise.reject(new Error("A")),
Promise.reject(new Error("B")),
]).catch((err) => {
console.log(err instanceof AggregateError); // true のことが多い
console.log(err.errors); // [Error("A"), Error("B")] のような配列
});
JavaScript細かい仕様を全部覚える必要はありませんが、
全部失敗した場合は、「複数の失敗理由」を中に持ったエラーが来る
ということだけ知っておくと、ログを眺めるときに混乱しにくくなります。
ここが重要です。Promise.any の catch に来るのは、「本当に誰一人成功しなかった時だけ」。
そのときのエラーは、「みんなの失敗をまとめた AggregateError」になりやすい。
どんな場面で Promise.any を使うと嬉しいか
例1:ミラーサーバー(どれか 1 つから取れればいい)
例えば、
サーバー A にアクセス
サーバー B にも同じデータがある
サーバー C にもある
という「同じ内容を持つミラーサーバー」が複数ある状況を考えてみます。
「どれか 1 つでも返してくれればいい。
一番早く成功したサーバーの結果を使いたい。」
こういうときに Promise.any はピッタリです。
function fetchFromA() {
return fetch("https://server-a.example.com/data");
}
function fetchFromB() {
return fetch("https://server-b.example.com/data");
}
function fetchFromC() {
return fetch("https://server-c.example.com/data");
}
Promise.any([fetchFromA(), fetchFromB(), fetchFromC()])
.then((response) => {
console.log("どれかのサーバーが成功:", response.url);
})
.catch((err) => {
console.error("全部ダメだった…", err);
});
JavaScriptこの場合の動きは、
3 つのサーバーに同時にリクエストを投げる
→ 一番早く成功したレスポンスを採用
→ 他は結果としては無視
となります。
1 つ目が落ちても、2 つ目や 3 つ目が成功すれば OK なので、
「部分的な失敗には強いけど、完全なる全滅はエラーにしたい」 という用途に向いています。
例2:メイン手段+予備手段(フォールバック)
もう少し単純化した例として、
メインの処理(ちょっと速いがたまに失敗する)
予備の処理(少し遅いが安定している)
みたいなときにも使えます。
function mainSource() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const ok = Math.random() > 0.5;
if (ok) resolve("メインの結果");
else reject(new Error("メイン失敗"));
}, 200);
});
}
function backupSource() {
return new Promise((resolve) => {
setTimeout(() => {
resolve("バックアップの結果");
}, 500);
});
}
Promise.any([mainSource(), backupSource()])
.then((value) => {
console.log("採用された結果:", value);
})
.catch((err) => {
console.error("両方ダメだった:", err);
});
JavaScriptここでは、
メインが運良く成功すれば 200ms で終了
メインが失敗しても、バックアップが 500ms で成功すればそれを採用
という、「メイン+フォールバック」の形になります。
ここが重要です。Promise.any は、「いくつか候補があって、そのうち 1 つでも成功してくれればいい」という場面で真価を発揮します。
ちょっとした注意点とイメージ整理
他の Promise は止まらない(race と同じ)
Promise.any も race や all と同様、
他の Promise の実行を途中で止めるわけではありません。
最初に成功したものを採用したあとも、
裏では残りの Promise が resolve / reject されます。
「本当に途中でキャンセルしたい」場合は、
AbortController や独自のキャンセルロジックが別途必要になる、という点はPromise.race と同じです。
all / allSettled / race / any のざっくりマップ
ここまでいろいろ出てきたので、感覚的な整理だけしておきます。
全部成功してほしい → Promise.all
全員の結果(成功・失敗)を報告してほしい → Promise.allSettled
とにかく一番早いやつ(成功でも失敗でも) → Promise.race
どれか 1 つでも成功してくれればいい → Promise.any
ここが重要です。
「全員」「全員+状態」「最速」「誰か 1 人成功」の 4 パターンを持っておくと、
非同期処理を設計するときの選択肢が一気に増えます。
初心者向け「Promise.any」の押さえどころ
最後に、最低限ここだけは掴んでおけば OK、というポイントをまとめます。
Promise.any([p1, p2, p3]) は、「p1, p2, p3 のうち、最初に成功した 1 つの結果だけを then に渡す」関数。
成功は最初の 1 回だけ。
最初の成功が決まった時点で、any の結果は確定する(残りは無視)。
1 つでも成功すれば catch には来ない。
catch に来るのは「全員失敗したときだけ」で、そのときは AggregateError 的なエラーになる。
race は「最初に成功 or 失敗したやつ」が勝ち → 早い失敗も勝つ。any は「成功だけが勝者」、失敗はスルーされる → 全滅したときだけエラー。
ミラーサーバー、メイン+フォールバックなど、「候補が複数あってどれか 1 つでも成功してくれればいい」場面で使うと強い。
ここが重要です。Promise.any を「失敗をやり過ごして、最初の成功だけを拾ってくる“センサー”」として捉えると、
どんな場面で使えばいいかが自然と見えてきます。
練習としては、
何回かに 1 回だけ成功する Promise
必ず成功する Promise(少し遅い)
を用意して Promise.any に渡し、
何度か実行して「早めの成功」「遅めの成功」「全員失敗」のパターンを試してみると、any の性格が一気に体に馴染んでくるはずです。
