シングルスレッド言語である JavaScript は、コードの実行をブロックすることなく時間のかかるタスクを処理するために常に非同期プログラミングに依存してきました。長年にわたり、JavaScript で非同期性を処理するアプローチは大幅に進化し、より読みやすく、管理しやすく、推論しやすくなりました。コールバックから Promise、async/await まで、非同期 JavaScript の歴史を辿る旅にご案内します。
コールバックが広く採用される前の JavaScript の初期の頃、ほとんどの JavaScript コードは同期的に作成されました。同期コードとは、各操作がブロック方式で次々に実行されることを意味します。長時間実行される操作が発生すると、その操作が完了するまでスクリプト全体の実行が一時停止されます。
あなたが駅の切符売り場にいると想像してみてください。切符売人は 1 人だけです。あなたがチケットをリクエストすると、チケット販売者がリクエストの処理を開始します。同期モデルでは、チケット販売者がリクエストの処理を完了してチケットを手渡すまで、カウンターで待たなければなりません。この間、他の人はサービスを受けることができず、チケットカウンター全体がブロックされます。
これは同期 JavaScript コードの例です:
console.log("Before operation"); // Simulating a long-running operation for (let i = 0; i < 1000000000; i++) { // Performing some computation } console.log("After operation");
このコードでは、console.log ステートメントが順番に実行され、長時間実行される操作 (for ループ) によってスクリプトの実行が完了するまでブロックされます。 「操作後」メッセージは、ループの終了後にのみ記録されます。
同期コードは理解と推論が簡単ですが、特に時間のかかる操作を扱う場合には、いくつかの問題が発生します。
同期コードの制限を克服し、より良いユーザー エクスペリエンスを提供するために、非同期プログラミング手法が導入されました。非同期プログラミングでは、コードの残りの実行をブロックすることなく、長時間実行される操作をバックグラウンドで実行できるため、コールバックが導入されました。
コールバックは、非同期操作を処理する主な方法でした。コールバックは、単に別の関数に引数として渡される関数であり、非同期操作が完了すると後で実行されます。
鉄道の切符を購入したいと想像してください。駅のチケットカウンターに行き、特定の目的地へのチケットをリクエストします。切符売り手はあなたのリクエストを受け付け、列車の座席の空き状況を確認するまでお待ちいただくようお願いします。連絡先を伝えて待合室で待ちます。チケット販売者がリクエストを処理し、座席が利用可能になると、チケットの受け取りの準備ができていることを知らせるためにあなたの名前を呼びます。この例えでは、あなたの連絡先情報はコールバックです。これは、チケット販売者が非同期タスク (空席状況の確認とチケットの発行) が完了したときにあなたに通知する方法です。
このアナロジーが JavaScript のコールバックにどのように関係するかを次に示します。
コールバックのアプローチでは、非同期操作が完了すると呼び出される関数 (コールバック) を提供します。非同期関数はタスクを実行し、結果またはエラーを使ってコールバックを呼び出します。これにより、コードで非同期操作の結果を処理できるようになります。
Node.js でコールバックを使用して API 呼び出しを行う例を次に示します。
console.log("Before operation"); // Simulating a long-running operation for (let i = 0; i < 1000000000; i++) { // Performing some computation } console.log("After operation");
この例には、API 呼び出しをシミュレートする fetchData 関数があります。 URL パラメータとコールバック関数を引数として受け取ります。関数内では、setTimeout を使用して、コールバック関数を呼び出す前に 1000 ミリ秒 (1 秒) の遅延をシミュレートします。
コールバック関数は、最初の引数 (err) としてエラーを受け入れ、2 番目の引数 (data) としてデータを受け入れるという一般的な規則に従います。この例では、エラーを null に設定し、サンプル データ オブジェクトを提供することで、成功した API 呼び出しをシミュレートします。
fetchData 関数を使用するには、URL とコールバック関数を使用して呼び出します。コールバック関数内では、まず err 引数をチェックしてエラーが発生したかどうかを確認します。エラーが存在する場合は、console.error を使用してコンソールにログを記録し、戻って以降の実行を停止します。
エラーが発生しなかった場合は、console.log を使用して受信したデータをコンソールに記録します。
このコードを実行すると、非同期 API 呼び出しがシミュレートされます。 1 秒の遅延の後、コールバック関数が呼び出され、結果がコンソールに記録されます。
{ id: 1、名前: 'ジョン ドゥ' }
この例は、コールバックを使用して非同期 API 呼び出しを処理する方法を示しています。コールバック関数は引数として非同期関数 (fetchData) に渡され、エラーまたは結果のデータで非同期操作が完了すると呼び出されます。
コールバックは仕事を完了させましたが、いくつかの欠点がありました:
コールバックに関する課題に対処するために、Promise が ES6 (ECMAScript 2015) で導入されました。 Promise は、非同期操作の最終的な完了または失敗を表し、操作を連鎖させることができます。
約束を電車の切符のようなものだと考えてください。鉄道の切符を購入するとき、その切符は鉄道会社が電車に乗って目的地に到着できることを約束するものです。切符には、出発時刻、路線、座席番号などの列車に関する情報が記載されています。切符を手に入れたら、電車の到着を待ち、乗車準備ができたら切符を使って電車に乗ることができます。
この例えでは、電車の切符が約束です。これは、非同期操作 (列車の旅) の最終的な完了を表します。列車の準備ができるまで (非同期操作が完了するまで)、チケット (Promise オブジェクト) を保持します。 Promise が解決されると (電車が到着すると)、チケットを使用して電車に乗ることができます (解決された値にアクセスします)。
このアナロジーが JavaScript の Promise にどのように関係するかを次に示します。
Promise は、非同期操作を処理するための構造化された方法を提供し、電車の切符が電車の旅の計画と管理に役立つのと同じように、複数の操作を連鎖させ、より管理しやすい方法でエラーを処理できるようにします。
Promise を使用して API 呼び出しを行う例を次に示します。
console.log("Before operation"); // Simulating a long-running operation for (let i = 0; i < 1000000000; i++) { // Performing some computation } console.log("After operation");
このコードでは、fetchData 関数は Promise を返します。 Promise コンストラクターは、2 つの引数 (resolve と拒否) を受け入れる関数を受け取ります。これらの関数は、Promise の状態を制御するために使用されます。
Promise コンストラクター内で、前の例と同様に、setTimeout を使用して API 呼び出しをシミュレートします。ただし、コールバック関数を呼び出す代わりに、resolve 関数と拒否関数を使用して非同期結果を処理します。
エラーが発生した場合 (この例では、エラー変数をチェックしてシミュレートします)、エラーを指定して拒否関数を呼び出し、Promise を拒否する必要があることを示します。
エラーが発生しない場合は、データを使用してsolve 関数を呼び出し、受信したデータを使用して Promise を解決する必要があることを示します。
fetchData 関数を使用するには、.then() メソッドと .catch() メソッドを関数呼び出しに連鎖させます。 .then() メソッドは Promise の解決された値を処理するために使用され、.catch() メソッドは発生する可能性のあるエラーを処理するために使用されます。
Promise が正常に解決されると、解決されたデータを使用して .then() メソッドが呼び出され、console.log を使用してそのデータをコンソールに記録します。
エラーが発生して Promise が拒否された場合、err オブジェクトを使用して .catch() メソッドが呼び出され、console.error を使用してコンソールにログが記録されます。
Promise を使用すると、コールバックと比較して、非同期操作を処理するためのより構造化された読みやすい方法が提供されます。 Promise を使用すると、.then() を使用して複数の非同期操作をチェーンし、.catch() を使用してより集中的な方法でエラーを処理できます。
Promise はコールバックに関していくつかの方法で改善されました:
しかし、約束にはまだいくつかの制限がありました。複数の Promise を連鎖させると、コードが深くネストされる可能性があり、構文はそれほどきれいではありません。
ES8 (ECMAScript 2017) で導入された Async/await は、Promise の上に構築されており、より同期的に見える非同期コードの記述方法を提供します。
async/await を使用すると、同期コードのように見え、動作する非同期コードを作成できます。それは、あなたの代わりにチケットカウンターに行くパーソナルアシスタントがいるようなものです。アシスタントがチケットを持って戻ってくるのを待つだけで、戻ってきたら、旅行を続けることができます。
async/await を使用して API 呼び出しを行う例を次に示します。
console.log("Before operation"); // Simulating a long-running operation for (let i = 0; i < 1000000000; i++) { // Performing some computation } console.log("After operation");
このコードには、API エンドポイントを表す URL パラメーターを取る fetchData という非同期関数があります。関数内では、try/catch ブロックを使用して、API リクエスト中に発生する可能性のあるエラーを処理します。
fetch 関数の前に await キーワードを使用して、fetch によって返された Promise が解決されるまで実行を一時停止します。これは、関数が次の行に進む前に API リクエストが完了するまで待機することを意味します。
応答を受信したら、await response.json() を使用して応答本文を JSON として解析します。これも非同期操作であるため、解析が完了するまで await を使用します。
API リクエストと JSON 解析が成功すると、fetchData 関数からデータが返されます。
API リクエストまたは JSON 解析中にエラーが発生した場合、catch ブロックによってキャッチされます。 console.error を使用してエラーをコンソールに記録し、throw err を使用してエラーを再スローして呼び出し元に伝播します。
fetchData 関数を使用するには、main と呼ばれる非同期関数があります。 main 内で、データを取得する API エンドポイントの URL を指定します。
await fetchData(url) を使用して fetchData 関数を呼び出し、データが返されるのを待ちます。 API リクエストが成功すると、受信したデータがコンソールに記録されます。
API リクエスト中にエラーが発生した場合、main 関数の catch ブロックによってキャッチされます。 console.error.
を使用して、エラーをコンソールに記録します。最後に、main 関数を呼び出してプログラムの実行を開始します。
このコードを実行すると、フェッチ関数を使用して、指定された URL に対して非同期 API リクエストが作成されます。リクエストが成功すると、受信したデータがコンソールに記録されます。エラーが発生した場合は、エラーも捕捉され、ログに記録されます。
fetch 関数で async/await を使用すると、非同期 API リクエストを処理するクリーンで読みやすい方法が提供されます。これにより、同期コードのように見え、動作する非同期コードを作成できるため、理解と保守が容易になります。
結論として、コールバックから Promise、そして async/await に至るまでの非同期 JavaScript の進化は、より読みやすく、管理しやすく、保守しやすい非同期コードを目指す旅でした。各ステップは前のステップに基づいて構築されており、制限に対処し、開発者のエクスペリエンスを向上させています。
現在、async/await は広く使用されており、JavaScript で非同期操作を処理するための推奨される方法となっています。これにより、開発者はクリーンで簡潔、理解しやすい非同期コードを作成できるため、すべての JavaScript 開発者のツールボックスに含まれる貴重なツールとなります。
以上が非同期 JavaScript - コールバックから Async Await への旅の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。