Promise.all()

Promise.all(iterable) メソッドは単一の Promise を返し、これは引数 iterable の中のすべての Promise が解決されるか、引数 iterable の中に Promise がない場合に解決されます。最初に拒否された Promise の拒否理由をもって拒否されます。

構文

Promise.all(iterable);

引数

iterable
ArrayString のような反復処理可能 (iterable) なオブジェクト。

返値

  • 渡した iterable が空の場合、解決済みPromise
  • 渡した iterable に Promise がない場合、非同期に解決した Promise。ただし、 Google Chrome 58 ではこの場合。すでに解決した Promise を返す。
  • その他の場合は待ち状態Promise 。この返却される promise は次に、 iterable として与えられたすべての Promise が解決するか、すべての Promise が拒否されると非同期に (スタックが空になるとすぐに) 解決/拒否されます。以下の「Promise.all の非同期性・同期性」の例を見てください。返値は、実行完了の順とは関係なく、 Promise が渡された順に並びます。

解説

このメソッドは複数の Promise の結果を集約するのに便利です。

完成:
空の iterable が渡された場合、このメソッドはすでに解決した Promise を (同期的に) 返します。
渡された Promise のすべてが満たされるか、 Promise が渡されていない場合、 Promise.all によって返される Promise が非同期的に完成されます。
すべての場合で、返された Promise は、引数として渡された iterableすべての値 (Promise ではない値も) を含んだ配列で完成されます。

拒否:
渡された Promise のいずれかが拒否されたら、 Promise.all は非同期的に、その他の Promise が完了しているかどうかに関係なく、その拒否した Promise の値で拒否されます。

Promise.all の使用

Promise.allはすべての完成 (または最初の拒否) を待ちます。

var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("foo");
  }, 100);
});

Promise.all([p1, p2, p3]).then(values => {
  console.log(values); // [3, 1337, "foo"]
});

iterable に Promise ではない値が含まれる場合は無視されますが、 (Promise が成功する場合) 返される Promise 配列の値にはカウントされます。

// this will be counted as if the iterable passed is empty, so it gets fulfilled
var p = Promise.all([1,2,3]);
// this will be counted as if the iterable passed contains only the resolved promise with value "444", so it gets fulfilled
var p2 = Promise.all([1,2,3, Promise.resolve(444)]);
// this will be counted as if the iterable passed contains only the rejected promise with value "555", so it gets rejected
var p3 = Promise.all([1,2,3, Promise.reject(555)]);

// using setTimeout we can execute code after the stack is empty
setTimeout(function() {
    console.log(p);
    console.log(p2);
    console.log(p3);
});

// logs
// Promise { <state>: "fulfilled", <value>: Array[3] }
// Promise { <state>: "fulfilled", <value>: Array[4] }
// Promise { <state>: "rejected", <reason>: 555 }

Promise.all の非同期性・同期性

以下の例では Promise.all の非同期性 (または渡されたiterable が空の場合、同期性) を実演します。

// we are passing as argument an array of promises that are already resolved,
// to trigger Promise.all as soon as possible
var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

var p = Promise.all(resolvedPromisesArray);
// immediately logging the value of p
console.log(p);

// using setTimeout we can execute code after the stack is empty
setTimeout(function() {
    console.log('the stack is now empty');
    console.log(p);
});

// logs, in order:
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }

Promise.all が拒否されたときも同じことが起きます.。

var mixedPromisesArray = [Promise.resolve(33), Promise.reject(44)];
var p = Promise.all(mixedPromisesArray);
console.log(p);
setTimeout(function() {
    console.log('the stack is now empty');
    console.log(p);
});

// logs
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "rejected", <reason>: 44 }

しかし、Promise.all は渡された iterable が空の場合だけ同期的に解決します。

var p = Promise.all([]); // will be immediately resolved
var p2 = Promise.all([1337, "hi"]); // non-promise values will be ignored, but the evaluation will be done asynchronously
console.log(p);
console.log(p2)
setTimeout(function() {
    console.log('the stack is now empty');
    console.log(p2);
});

// logs
// Promise { <state>: "fulfilled", <value>: Array[0] }
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }

Promise.allのフェイルファストの挙動

Promise.all は要素のひとつでも拒否されると拒否します。例えば、タイムアウト後に4つの Promise が解決しても、1つの Promise が直ちに拒否された場合、 Promise.all は直ちに拒否します。

var p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('one'), 1000);
});
var p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('two'), 2000);
});
var p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('three'), 3000);
});
var p4 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('four'), 4000);
});
var p5 = new Promise((resolve, reject) => {
  reject(new Error('reject'));
});


// Using .catch:
Promise.all([p1, p2, p3, p4, p5])
.then(values => {
  console.log(values);
})
.catch(error => {
  console.log(error.message)
});

//From console:
//"reject"

この動作は失敗する可能性を制御することで変更することができます。

var p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('p1_delayed_resolvement'), 1000);
});

var p2 = new Promise((resolve, reject) => {
  reject(new Error('p2_immediate_rejection'));
});

Promise.all([
  p1.catch(error => { return error }),
  p2.catch(error => { return error }),
]).then(values => {
  console.log(values[0]) // "p1_delayed_resolvement"
  console.log(values[1]) // "Error: p2_immediate_rejection"
})

仕様書

仕様書 状態 備考
ECMAScript 2015 (6th Edition, ECMA-262)
Promise.all の定義
標準 ECMA 標準としての初回定義
ECMAScript (ECMA-262)
Promise.all の定義
現行の標準  

ブラウザーの対応

BCD tables only load in the browser

関連情報