【実践編】JavaScriptでPromise.allSettled()を使って、全てのPromiseの結果を取得する方法
JavaScript ですべての Promise が完了するまで待機する方法(一部拒否されても)
しかし、複数の Promise を実行する場合、すべての Promise が完了するまで待機したいことがあります。また、一部の Promise が拒否されても、残りの Promise の結果を取得したい場合もあります。
以下では、すべての Promise が完了するまで待機する方法と、一部の Promise が拒否されても、残りの Promise の結果を取得する方法について、ES6 Promise を使って詳しく解説します。
Promise.all() を使用する
Promise.all() は、与えられたすべての Promise が完了するのを待って、それらの結果を配列として返す関数です。すべての Promise が正常に完了した場合のみ、Promise.all()
は成功した Promise を返します。1つでも Promise が拒否されると、Promise.all() は即座に拒否され、拒否された理由を伝えるエラー情報を含む Promise を返します。
以下は、Promise.all()
を使ってすべての Promise が完了するまで待機する例です。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise 1 resolved'), 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Promise 2 rejected')), 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise 3 resolved'), 3000);
});
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // 結果: [ 'Promise 1 resolved', 'Promise 3 resolved' ] (Promise 2 は拒否されたため、results には含まれません)
})
.catch(error => {
console.error(error); // エラー: Error: Promise 2 rejected
});
この例では、promise2
が拒否されているため、Promise.all()
は拒否され、console.error()
にエラー情報が出力されます。
Promise.allSettled() を使用する
Promise.allSettled() は、与えられたすべての Promise が完了するのを待って、それらの結果をPromise オブジェクトの配列として返す関数です。Promise.all()
と異なり、すべての Promise の完了結果 (成功または失敗) を取得できます。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise 1 resolved'), 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Promise 2 rejected')), 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise 3 resolved'), 3000);
});
Promise.allSettled([promise1, promise2, promise3])
.then(results => {
console.log(results);
// 結果: [ { status: 'fulfilled', value: 'Promise 1 resolved' },
// { status: 'rejected', reason: Error: Promise 2 rejected },
// { status: 'fulfilled', value: 'Promise 3 resolved' } ]
});
この例では、promise2
が拒否されていますが、Promise.allSettled()
はすべての Promise の結果を含む Promise オブジェクトの配列を返します。各 Promise オブジェクトには、status
プロパティ ('fulfilled'
または 'rejected'
) と、value
または reason
プロパティ (Promise の結果またはエラー情報) が含まれます。
async/await を使用する
async/await は、Promise をより同期的に扱うための構文です。async
キーワードでマークされた関数は、Promise を返します。await
キーワードを使って、非同期処理の結果を待つことができます。
async function main() {
const promise1 = new Promise((resolve, reject) => {
setTimeout(() =>
JavaScript ですべての Promise が完了するまで待機するサンプルコード(一部拒否されても)
Promise.all() を使用する
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise 1 resolved'), 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Promise 2 rejected')), 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise 3 resolved'), 3000);
});
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // 結果: [ 'Promise 1 resolved', 'Promise 3 resolved' ] (Promise 2 は拒否されたため、results には含まれません)
})
.catch(error => {
console.error(error); // エラー: Error: Promise 2 rejected
});
解説:
- このコードは、3 つの Promise を作成します。
Promise.all()
が成功した場合、then()
ハンドラが呼び出され、Promise の結果がresults
配列に格納されます。Promise.all()
が失敗した場合、catch()
ハンドラが呼び出され、エラー情報がコンソールに出力されます。
Promise.allSettled() を使用する
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise 1 resolved'), 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Promise 2 rejected')), 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise 3 resolved'), 3000);
});
Promise.allSettled([promise1, promise2, promise3])
.then(results => {
console.log(results);
// 結果: [ { status: 'fulfilled', value: 'Promise 1 resolved' },
// { status: 'rejected', reason: Error: Promise 2 rejected },
// { status: 'fulfilled', value: 'Promise 3 resolved' } ]
});
- 各 Promise オブジェクトには、
status
プロパティ ('fulfilled'
または'rejected'
) と、value
またはreason
プロパティ (Promise の結果またはエラー情報) が含まれます。
async/await を使用する
async function main() {
const result1 = await promise1;
const result2 = await promise2;
const result3 = await promise3;
console.log(result1, result2, result3);
}
main().catch(error => {
console.error(error);
});
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise 1 resolved'), 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Promise 2 rejected')), 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('Promise 3 resolved'), 3000);
});
- このコードは、
async
関数main()
を定義します。 await
キーワードを使って、promise1
、promise2
、promise3
の結果を順番に待ちます。catch()
ハンドラを使って、非同期処理中に発生するエラーを処理します。
補足:
- 上記のコードはあくまで一例です。状況に応じて、適切な方法を選択してください。
- より複雑な処理の場合は、エラー
JavaScriptで全てのPromiseが完了するまで待機する方法(一部拒否されても) - その他の方法
自作のPromise関数:
以下のコードは、Promise.all() や Promise.allSettled() と同様の機能を持つ自作のPromise関数です。全てのPromiseが完了し、結果またはエラー情報を含む配列を返します。
function myAll(promises) {
const results = [];
let errors = [];
return new Promise((resolve, reject) => {
let pending = promises.length;
promises.forEach((promise, i) => {
promise.then(result => {
results[i] = result;
pending--;
if (pending === 0) {
resolve(results);
}
}).catch(error => {
errors.push(error);
pending--;
if (pending === 0) {
if (errors.length > 0) {
reject(errors[0]);
} else {
reject(new Error('All promises rejected'));
}
}
});
});
});
}
この関数は、以下の例のように使用できます。
myAll([promise1, promise2, promise3])
.then(results => console.log(results))
.catch(error => console.error(error));
再帰処理:
以下のコードは、再帰処理を使って全てのPromiseが完了するまで待機する方法です。
function allRecursive(promises, results = [], errors = []) {
if (promises.length === 0) {
if (errors.length > 0) {
return Promise.reject(errors[0]);
} else {
return Promise.resolve(results);
}
}
const promise = promises.shift();
return promise.then(result => {
results.push(result);
return allRecursive(promises, results, errors);
}).catch(error => {
errors.push(error);
return allRecursive(promises, results, errors);
});
}
allRecursive([promise1, promise2, promise3])
.then(results => console.log(results))
.catch(error => console.error(error));
外部ライブラリの利用:
Bluebird や Q などの外部ライブラリには、Promise.all()
や Promise.allSettled()
と同様の機能を持つメソッドが用意されています。これらのライブラリを使用することで、より簡単に全てのPromiseを処理することができます。
注意事項:
上記の方法はいずれも、非同期処理を扱うため、コードの理解と注意が必要です。また、状況に応じて適切な方法を選択する必要があります。
javascript promise es6-promise