ホームページ >ウェブフロントエンド >jsチュートリアル >Promise.all() を使用して複数の Promise を同時に管理する方法
JavaScript の非同期プログラミングを使用すると、メインスレッドを中断することなく、リソースを大量に消費する操作をバックグラウンドで実行できます。 API 呼び出しやファイル処理などの操作は、非同期で実行する必要がある操作の一部です。
約束。 all() は、これらの操作を同時に管理できる強力な関数です。この記事では、Promise.all()
を使用して複数の Promise を同時に管理する方法について説明します。詳しく見ていきましょう。
Promise は、非同期イベントの最終的な失敗または完了を表すオブジェクトです。簡単な約束を見てみましょう。
const userId = 1; let promise = new Promise((resolve, reject) => { setTimeout(() => { if (userId === 1) { resolve({ name: "John Doe", email: "john@example.com" }); } else { reject(new Error("User not found")); } }, 1000); });
Promise は 2 つのパラメータ、resolve と accept を持つ関数を受け取ります。この例では、操作が成功した場合 (つまり userId===1 の場合)、Promise は解決されます。操作が失敗した場合、Promise は拒否されます。
Promise のライフサイクルは保留状態で開始され、最終的には履行されるか拒否されます。現在、約束は保留中です。 Promise を使用するには、.then() を呼び出して結果を処理します。
出力は、ユーザー データ (満たされた場合) またはエラー (拒否された場合) のいずれかになります。
promise .then((data) => { console.log(data); }) .catch((err) => { console.log(err); });
操作が成功したため、Promise は解決されます。
const userId = 1; let promise = new Promise((resolve, reject) => { setTimeout(() => { if (userId === 1) { resolve({ name: "John Doe", email: "john@example.com" }); } else { reject(new Error("User not found")); } }, 1000); }); promise .then((data) => { console.log(data); }) .catch((err) => { console.log(err); });
userId の値を変更すると、Promise は拒否され、「ユーザーが見つかりません」というエラーが表示されます
複数の Promise があると仮定すると、次のように各 Promise を個別に処理します。
const promise1 = new Promise((resolve, reject) => resolve(1)); const promise2 = new Promise((resolve, reject) => resolve(2)); const promise3 = new Promise((resolve, reject) => resolve(3)); promise1 .then((value) => { console.log(value); promise2 .then((value) => { console.log(value); promise3 .then((value) => { console.log(value); }) .catch((err) => { console.log("promise3 error", err); }); }) .catch((err) => { console.log("promise2 error", err); }); }) .catch((err) => { console.log("promise1 error", err); });
上記の実行により、いくつかの潜在的な問題が発生します:
各 Promise は、前の Promise が完了した後に実行されます。 promise2 は、promise1 が解決された後に開始され、promise3 は、promise2 が解決された後に開始されます。これにより、実行が遅くなります。
.then チェーンの入れ子構造により、「コールバック地獄」 が発生し、コードの読み取りと保守が困難になります。
各エラーは個別に処理されるため、さらに複雑になります。
より良いアプローチは、Promise.all() を使用することです。これにより、Promise を同時に実行できるため、パフォーマンスとエラー処理が向上します
Promise.all() は、反復可能な Promise を受け取り、単一の Promise を返します。構文は次のようになります:
Promise.all(iterable)
Promise.all() を使用する場合、前の例では次のようになります。
Promise.all([promise1, promise2, promise3]) .then((values) => { console.log(values); }) .catch((err) => { console.log("promise all error", err); });
ご覧のとおり、このアプローチはより明確で理解しやすくなっています。
JavaScript はシングルスレッド言語です。つまり、各コードは前のコードが完了するのを待ってから次のコードに進みます。
では、JavaScript がシングルスレッドの場合、Promise.all() は複数の Promise をどのように処理するのでしょうか?
Promise.all() は同時実行の原則に基づいて動作します。つまり、すべての Promise は必ずしも同時に実行を開始するわけではありませんが、ある Promise の完了を待たずに次の Promise を開始します。
Promise.all() は、反復可能内のすべての Promise が満たされた場合にのみ解決されます。ただし、反復可能内のいずれかの Promise が拒否された場合、Promise.all() は直ちに拒否され、残りの Promise の結果は無視されます。
Promise.all() は、複数の独立した非同期操作を実行し、すべての操作が完了するまで待ってから続行する必要があるシナリオに優れています。
実際のアプリケーションの効率を向上させるために Promise.all() を使用できる例をいくつか見てみましょう。
2 つの異なる API から同時にデータを取得するアプリケーションに取り組んでいるシナリオを考えてみましょう。
複数の API からデータを順番に取得して、リクエストが完了するまでにかかった時間を記録してみましょう。
const userId = 1; let promise = new Promise((resolve, reject) => { setTimeout(() => { if (userId === 1) { resolve({ name: "John Doe", email: "john@example.com" }); } else { reject(new Error("User not found")); } }, 1000); });
出力は次のとおりです:
リクエストの処理にかかる時間は 50.36 ミリ秒です。この実行時間は改善できる可能性があります。同時実行のメリットを説明するために、Promise.all()
を使用したアプローチを比較してみましょう。
promise .then((data) => { console.log(data); }) .catch((err) => { console.log(err); });
ここでは Promise.all() を使用して複数の非同期操作を同時に実行しています。 Promise.all() は、Promise の配列を受け取り、すべての Promise が解決されたときに 1 つの Promise を返します。
これが出力です。
出力から、Promise.all() を使用する方が若干効率的であることがわかります。この改善は、Promise.all() を使用すると、一方の操作が終了するのを待ってからもう一方の操作を開始するのではなく、両方の操作を同時に開始できるためです。
より複雑な操作や追加の API 呼び出しを伴う実際のアプリケーションでは、Promise.all() を使用することでパフォーマンスがさらに大幅に向上する可能性があります。
ただし、履行するか拒否するかに関係なく、すべての Promise が解決するのを待ちたい場合は、Promise.allSettled()
を使用できます。この場合、すべてのデータを同時に送信する必要があります。この場合、Promise.all() を使用してすべてのリクエストを同時に送信し、結果を取得する前にすべてのリクエストが解決されるまで待つことができます。
たとえば、次のサンプル データを分析する必要があるとします。
const userId = 1; let promise = new Promise((resolve, reject) => { setTimeout(() => { if (userId === 1) { resolve({ name: "John Doe", email: "john@example.com" }); } else { reject(new Error("User not found")); } }, 1000); });
この場合、すべてのデータを一度に送信する必要があります。データを順番に送信すると時間がかかります。代わりに、Promise.all() を使用して複数の API 呼び出しを同時に開始します。
次のようなものになります:
promise .then((data) => { console.log(data); }) .catch((err) => { console.log(err); });
ユーザーからの一括アップロードを受け入れるアプリケーションがあるとします。ファイルを検証するために必要な措置をすべて講じた後、Promise.all() を使用して複数のファイルの読み取りを並行して実行できます。これは、各ファイルを 1 つずつ順番に読み取るよりもはるかに効率的です。
Promise.all() を使用しない場合、次のファイルを読み取る前に、各ファイルが完全に読み取られるまで待つ必要があります。これにより、特にファイル数が多い場合、処理時間が長くなります。
ただし、Promise.all() を使用すると、すべてのファイル読み取り操作が同時に開始されるため、大幅な時間の節約と優れたユーザー エクスペリエンスが得られます。
const userId = 1; let promise = new Promise((resolve, reject) => { setTimeout(() => { if (userId === 1) { resolve({ name: "John Doe", email: "john@example.com" }); } else { reject(new Error("User not found")); } }, 1000); }); promise .then((data) => { console.log(data); }) .catch((err) => { console.log(err); });
多くの大きなファイルを同時に読み取る場合は、潜在的なメモリの考慮事項に注意する必要があることに注意することも重要です。
結論として、Promise.all() には以下にまとめた多くの利点があります
よりクリーンなコード: Promise.all() を使用すると、ネストされた .then() チェーンがないため、コードが理解しやすくなります。リクエストは単一の .then() ブロックで処理されます。
効率的: リクエストを同時に実行すると、データのフェッチに必要な合計時間が短縮されるため、アプリケーションの全体的なパフォーマンスが向上します。
実用的な JavaScript のヒントとコード スニペットが受信箱に届きます。より良いコードを書く 1,000 人の開発者に加わりましょう。
以上がPromise.all() を使用して複数の Promise を同時に管理する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。