Asa Tech Blog

学んだことを備忘録として残しています

Promise.allとPromise.allSettledの違い

大量のメール送信処理などで、非同期処理を複数実行する必要がある場合に、効率的に並列で実行できるメソッドとしてPromise.all()があります。 Promise.allを使う中で、もしかして、途中で失敗する非同期処理があったら、すべて処理が実行されなくなるのではと疑問に思ったので、Promise.allの挙動を調べることにしました。

Promise.all

Promise.allは、MDNでは以下のように説明されています。

Promise.all() メソッドは入力としてプロミスの集合の反復可能オブジェクトを取り、入力したプロミスの集合の結果の配列に解決される単一の Promise を返します。この返却されたプロミスは、入力したプロミスがすべて解決されるか、入力した反復可能オブジェクトにプロミスが含まれていない場合に解決されます。入力したプロミスのいずれかが拒否されるか、プロミス以外のものがエラーを発生させると直ちに拒否され、最初に拒否されたメッセージまたはエラーをもって拒否されます。 Promise.all() - JavaScript | MDN

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.error(error.message)
});

//From console:
//"reject"

Promise.all() では、複数あるPromiseの実行が1つでもrejectを返すと、Promise.all は直ちに拒否されるようです。

Promise.allSettled

Promise.allSettled() メソッドは、与えられたすべてのプロミスが履行されたか拒否された後に、それぞれのプロミスの結果を記述した配列オブジェクトで解決されるプロミスを返します。

Promise.allSettled([
  Promise.resolve(33),
  new Promise(resolve => setTimeout(() => resolve(66), 0)),
  99,
  Promise.reject(new Error('an error'))
])
.then(values => console.log(values));

// [
//   {status: "fulfilled", value: 33},
//   {status: "fulfilled", value: 66},
//   {status: "fulfilled", value: 99},
//   {status: "rejected",  reason: Error: an error}
// ]

Promise.allSettledでは、Promiseがrejectされてもそのまま処理が続くようです。

まとめ

Promiseが失敗しても、処理を続けたいという場合は、Promise.allSettledを使ったほうが良さそうです