Promise.any()

Promise.any()Promise オブジェクトの反復可能オブジェクトを受け取り、反復可能オブジェクトの中にあるプロミスの一つが満足するとすぐに、そのプロミスの値で解決される単一のプロミスを返します。反復可能オブジェクトの中に満足可能なプロミスがない場合 (与えられたプロミスがすべて拒否された場合)、返されたプロミスは AggregateError という、個々のエラーをグループ化した Error の新しいサブクラスで拒否されます。本質的には、このメソッドは Promise.all() の反対です。

警告! Promise.any() メソッドは実験的であり、すべてのブラウザーが対応しているわけではありません。現在は TC39 Candidate stage (Stage 4) にあります。

構文

Promise.any(iterable);

引数

iterable
反復可能オブジェクト、例えば Array です。

返値

  • 渡された iterable が空の場合は、解決済みの Promise
  • 渡された iterable がプロミスを含んでいない場合は、非同期に解決される Promise
  • それ以外の場合は待ち状態の Promise。ここで返されたプロミスは、与えられた反復可能オブジェクト内のいずれかのプロミスが満足したとき、またはすべてのプロミスが拒否されたときに、非同期的に (スタックが空になるとすぐに) 解決または拒否されます。

解説

このメソッドは、最初に満足するプロミスを返すのに便利です。1つのプロミスが満足した後に短絡するので、1つのプロミスが見つかったら他のプロミスが満足するのを待つことはありません。 Promise.all() が満足した値の配列を返すのとは異なり、 (少なくとも1つのプロミスが満足したと仮定すると) 満足した値は 1 つしか得られません。これは、1つのプロミスが満足する必要があるが、どちらのプロミスが満足するかは関係ないときに有益な場合があります。また Promise.race() が最初に完了した値 (満足または拒否のいずれか) を返すのとは異なり、このメソッドは最初に満足した値を返します。このメソッドは、最初のプロミスが満足するまでは、すべての拒否されたプロミスを無視します。

満足

渡されたプロミスのうちのいずれかが満足した場合、返却されるプロミスは他のプロミスが満足または拒否されているかどうかにかかわらず、満足したプロミスの値で非同期に満足します。

  • 空の iterable が渡された場合は、このメソッドはすでに解決済みのプロミスを (同期的に) 返します。
  • 渡されたプロミスのいずれかが満足するか、プロミスがない場合は、 Promise.any で返されるプロミスは非同期で満足します。

拒否

渡されたすべてのプロミスが拒否された場合、 Promise.anyAggregateError オブジェクトで非同期に拒否され、これはError を継承しており、拒否された値の配列を持つ errors プロパティを含みます。

最初に満足するもの

Promise.any() は、先に拒否されたプロミスがあったとしても、最初に満足したプロミスで解決されます。これは Promise.race() が最初に決定したプロミスで解決または拒否されるのとは対照的です。

const pErr = new Promise((resolve, reject) => {
  reject("Always fails");
});

const pSlow = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "Done eventually");
});

const pFast = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "Done quick");
});

Promise.any([pErr, pSlow, pFast]).then((value) => {
  console.log(value);
  // pFast fulfils first
})
// 期待される出力: "Done quick"

AggregateError での拒否

Promise.any() は満足したプロミスがないと AggregateError で拒否されます。

const pErr = new Promise((resolve, reject) => {
  reject('Always fails');
});

Promise.any([pErr]).catch((err) => {
  console.log(err);
})
// 期待される出力: "AggregateError: No Promise in Promise.any was resolved"

最初に読み込まれた画像の表示

この例では、画像を読み込んで blob を返す関数があります。 Promise.any() を使用して二つの画像を読み込み、先に利用可能になった方 (つまり、プロミスが解決された方) を表示します。

function fetchAndDecode(url) {
  return fetch(url).then(response => {
    if(!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    } else {
      return response.blob();
    }
  })
}

let coffee = fetchAndDecode('coffee.jpg');
let tea = fetchAndDecode('tea.jpg');

Promise.any([coffee, tea]).then(value => {
  let objectURL = URL.createObjectURL(value);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
})
.catch(e => {
  console.log(e.message);
});

仕様書

仕様書
Promise.any

ブラウザーの互換性

BCD tables only load in the browser

関連情報