Promise.all()
TypeScriptにおけるPromise.all()の使い方
基本的な使い方
const promise1 = Promise.resolve(10);
const promise2 = Promise.resolve(20);
const promise3 = Promise.resolve(30);
Promise.all([promise1, promise2, promise3])
.then((values) => {
console.log(values); // [10, 20, 30] が出力される
})
.catch((error) => {
console.error(error);
});
上記の例では、promise1
、promise2
、promise3
という3つのPromiseを同時に実行し、全てが完了したらthen
ハンドラ内の処理を実行しています。values
には、各Promiseの完了値が配列として格納されます。
エラー処理
**Promise.all()**は、一つでもPromiseが失敗したら即座に全体が失敗扱いとなります。そのため、エラー処理を丁寧に行うことが重要です。
const promise1 = Promise.resolve(10);
const promise2 = Promise.reject(new Error('エラー発生'));
const promise3 = Promise.resolve(30);
Promise.all([promise1, promise2, promise3])
.then((values) => {
console.log(values); // 処理されない
})
.catch((error) => {
console.error(error.message); // 'エラー発生' が出力される
});
上記の例では、promise2
が失敗しているため、then
ハンドラは実行されず、catch
ハンドラ内のエラー処理が実行されます。
型注釈
TypeScriptでは、**Promise.all()**の返り値の型も適切に注釈することができます。
const promise1: Promise<number> = Promise.resolve(10);
const promise2: Promise<number> = Promise.resolve(20);
const promise3: Promise<number> = Promise.resolve(30);
Promise.all([promise1, promise2, promise3])
.then((values: number[]) => {
console.log(values); // 型注釈により、valuesがnumber型の配列であることが保証される
})
.catch((error) => {
console.error(error);
});
非同期処理の同時実行
**Promise.all()**は、ネットワークリクエストやファイル読み込みなど、非同期処理を効率的に実行したい場面で威力を発揮します。以下の例のように、複数のAPIを同時に呼び出し、結果をまとめて処理することができます。
const getUserData = (userId: number) => {
return fetch(`https://api.example.com/users/${userId}`)
.then((response) => response.json());
};
const getPhotoData = (photoId: number) => {
return fetch(`https://api.example.com/photos/${photoId}`)
.then((response) => response.json());
};
Promise.all([
getUserData(123),
getPhotoData(456),
])
.then((values) => {
const userData = values[0];
const photoData = values[1];
console.log({ userData, photoData });
})
.catch((error) => {
console.error(error);
});
上記の例では、getUserData
とgetPhotoData
という2つの非同期処理を同時に実行し、結果を組み合わせて処理しています。
**Promise.all()**は、非同期処理を効率的に扱い、コードをより読みやすく、保守しやすいものにするのに役立つ強力なツールです。ぜひ積極的に活用してみてください。
補足
- Promise.allSettled(): **Promise.all()**と似ていますが、全てのPromiseが完了するまで待機し、成功・失敗にかかわらず結果を配列で返します。エラー処理にも利用できます。
- async/await: **Promise.all()**と併用することで、非同期処理をより直感的に記述することができます。
TypeScriptにおけるPromise.all()のサンプルコード
この例では、Promise.resolve()
を使用して生成された3つのPromiseを同時に実行し、then
ハンドラで結果を出力します。
const promise1 = Promise.resolve(10);
const promise2 = Promise.resolve(20);
const promise3 = Promise.resolve(30);
Promise.all([promise1, promise2, promise3])
.then((values) => {
console.log(values); // [10, 20, 30] が出力される
})
.catch((error) => {
console.error(error);
});
この例では、Promise.reject()
を使用してエラーを生成するPromiseを含め、エラー処理をどのように行うかを示しています。
const promise1 = Promise.resolve(10);
const promise2 = Promise.reject(new Error('エラー発生'));
const promise3 = Promise.resolve(30);
Promise.all([promise1, promise2, promise3])
.then((values) => {
console.log(values); // 処理されない
})
.catch((error) => {
console.error(error.message); // 'エラー発生' が出力される
});
この例では、型注釈を使用して、Promise.all()
の返り値の型を明確にしています。
const promise1: Promise<number> = Promise.resolve(10);
const promise2: Promise<number> = Promise.resolve(20);
const promise3: Promise<number> = Promise.resolve(30);
Promise.all([promise1, promise2, promise3])
.then((values: number[]) => {
console.log(values); // 型注釈により、valuesがnumber型の配列であることが保証される
})
.catch((error) => {
console.error(error);
});
この例では、fetch()
を使用して2つのAPIリクエストを非同期に実行し、結果を組み合わせてコンソールに出力する方法を示しています。
const getUserData = (userId: number) => {
return fetch(`https://api.example.com/users/${userId}`)
.then((response) => response.json());
};
const getPhotoData = (photoId: number) => {
return fetch(`https://api.example.com/photos/${photoId}`)
.then((response) => response.json());
};
Promise.all([
getUserData(123),
getPhotoData(456),
])
.then((values) => {
const userData = values[0];
const photoData = values[1];
console.log({ userData, photoData });
})
.catch((error) => {
console.error(error);
});
- async/await: 上記の例は、非同期処理をより簡潔に記述するために、
async/await
構文を使用することもできます。 - Promise.allSettled(): すべてのPromiseが完了するまで待機し、成功・失敗にかかわらず結果を配列で返す
Promise.allSettled()
もあります。
これらのサンプルコードを参考に、Promise.all()
を様々な場面で活用してみてください。
Promise.all()の代替案
forEach()とPromise.resolve()の組み合わせ
const promises = [
Promise.resolve(10),
Promise.resolve(20),
Promise.resolve(30),
];
let result = [];
promises.forEach((promise) => {
promise.then((value) => {
result.push(value);
});
});
Promise.resolve(result).then((values) => {
console.log(values); // [10, 20, 30] が出力される
});
この方法は、**Promise.all()**よりも冗長になりますが、個々のPromiseの完了処理をより細かく制御することができます。
async/awaitとforループの組み合わせ
const promises = [
Promise.resolve(10),
Promise.resolve(20),
Promise.resolve(30),
];
let result = [];
for (const promise of promises) {
const value = await promise;
result.push(value);
}
console.log(result); // [10, 20, 30] が出力される
RxJSなどのライブラリを使用する
RxJSなどのライブラリは、Promiseよりも強力な非同期処理の管理機能を提供しています。これらのライブラリを使用すると、**Promise.all()**よりも柔軟で高機能な処理を記述することができます。
個別に処理を実行する
それぞれのPromiseが独立している場合は、個別に処理を実行することもできます。この方法は、最もシンプルですが、処理の順番を制御する必要がでてきます。
どの方法を選択するかは、状況によって異なります。 以下のような点を考慮して、適切な方法を選択してください。
- 処理の複雑さ
- 処理の順番
- エラー処理のニーズ
- 個人的な好み
**Promise.all()**は万能なツールではありませんが、多くの場合で非常に役立ちます。上記で紹介した代替案も理解しておくと、より柔軟な非同期処理の記述が可能になります。
typescript