コールバック関数は、引数として別の関数に渡される関数であり、その後、外部関数内で呼び出され、ある種のルーチンまたはアクションを完了します。コールバックを呼び出す方法には、同期と非同期の 2 つがあります。これは、JavaScript の最も基本的な非同期パターンです。
例:
A と B は、メイン JS プログラムの直接制御下で実行されます。ただし、C は後で実行されるように延期され、別のパーティ (この場合は ajax(..) 関数) の制御下に置かれます。基本的な意味では、この種の制御の引き継ぎがプログラムに多くの問題を引き起こすことはあまりありません。
しかし、頻度が低いからといって問題や問題を無視するには十分ではありません。実際、これはコールバック駆動設計の大きな問題の 1 つです。これは、ajax(..) やコールバック継続を渡す「パーティ」が、自分で作成した関数ではない、または直接制御する関数ではない場合があるという考えを中心に展開しています。多くの場合、これはサードパーティによって提供されるユーティリティです。
ユーザーがプログラムの一部を取得し、その実行の制御を別のサードパーティに渡すことを、「制御の反転」と呼びます。コードとサードパーティ ユーティリティの間には、暗黙の「契約」が存在します。これは、維持されることが期待される一連のものです。
この問題をよりよく理解するための例があります。
会社のために旅行予約 Web サイトを構築しているとします。サードパーティ ライブラリの createBooking() 関数を使用する「今すぐ予約」ボタンを追加しました。この関数は予約を処理し、コールバックを呼び出して顧客に確認メールを送信します。
このコードは次のようになります:
テスト中はすべてが完璧に動作します。人々はあなたのウェブサイトで旅行パッケージを予約し始め、誰もがあなたの仕事に満足しています。ある日突然、上司から大きな問題について電話がかかってきました。お客様がパッケージを予約しましたが、1 件の予約に対して同一の確認メールを 4 通受け取りました。
問題のデバッグを開始します。確認メールを送信するコードの部分を確認すると、すべてが正しいようです。さらに詳しく調査すると、サードパーティ ライブラリの createBooking() ユーティリティがコールバック関数を 4 回呼び出し、その結果 4 通の確認メールが送信されたことがわかりました。
あなたはサードパーティ ライブラリのサポート チームに連絡し、状況を説明します。彼らは、これまでこの問題に遭遇したことはないが、優先順位を付けて折り返し連絡すると言います。 1 日後、結果を報告する電話がかかってきます。彼らは、公開される予定ではなかった実験的なコード部分が原因で、createBooking() 関数がコールバックを複数回呼び出す原因となっていたことを発見しました。
この問題は彼らの側にあり、彼らはそれが解決されたことを保証しました。彼らはトラブルについて謝罪し、問題が再び発生しないことを確認しました。
解決策を模索した後のこのような望ましくない問題を防ぐには、次のような単純な if ステートメントを実装します。チームはこれに満足しているようです。
しかし、QA エンジニアの 1 人が「コールバックを呼び出さなかったらどうなりますか?」と尋ねました。おっと。二人ともそんなこと考えもしませんでした!
あなたは、相手があなたのコールバックを呼び出すことで起こる可能性のあるあらゆる問題について考え始めます。以下にいくつかの問題のリストを示します:
コールバックの呼び出しが早すぎます
コールバックを呼び出すのが遅すぎる (またはコールバックを呼び出さない)
コールバックの呼び出し回数が少なすぎる、または多すぎる (上記の例の問題のように)
発生する可能性のあるエラー/例外を無視します
...
おそらく、さまざまな状況に応じて多くのソリューションをコードに実装する必要があることに気づくでしょう。ユーティリティに渡されるすべてのコールバックで必要となるため、コードがひどく汚くなってしまいます。
この制御の逆転を元に戻すことができたらどうなるでしょうか?プログラムの継続を別のパーティに渡す代わりに、そのタスクがいつ終了したかを知る機能を返すことを期待でき、その後、コードが次に何をするかを決定できるとしたらどうなるでしょうか?
Promise は、JavaScript で非同期操作を処理する強力な方法を提供し、コールバック地獄や制御の反転などの問題に対処します。コールバックとは異なり、Promises を使用すると、コードの制御を放棄することなく非同期タスクを管理できます。
ファストフードレストランでチーズバーガーを注文することを考えてみましょう。あなたは、将来のチーズバーガーを約束するレシートを受け取ります。待っている間、最終的には注文が届くと考えて、他のことをすることができます。同様に、JavaScript の Promise は将来の値を表すため、コードをスムーズに進めることができます。
レストランでチーズバーガーが切れた場合に通知されるのと同じように、Promise は失敗にも適切に対処します。この構造により、コードがより読みやすく、保守しやすくなります。
ここでは Promise について詳しく説明しませんが、Promise を使用すると、よりクリーンで信頼性の高い非同期コードを作成でき、JavaScript アプリケーションの全体的な品質が向上します。
たとえば、前に説明した旅行予約 Web サイトの場合、サードパーティのユーティリティが Promise を返した場合、次のように処理できます。
Promise が解決される (正常に完了する) と、その状態は永久に維持されます。その時点で Promise は不変の値となり、その後は必要に応じて何度でも監視できます。これは、解決された Promise を意味し、その解決された値は、その状態に影響を与えることなく、コード内で何度もアクセスまたは使用できます。これにより、Promise の変更や再評価を心配することなく、アプリケーションのさまざまな部分で非同期操作の結果を処理できるようになります。
Promise は、コールバックのみのコードで発生する制御の反転の問題に対する解決策です。コールバックは制御の反転を表します。したがって、コールバック パターンを反転することは、実際には反転の反転、または制御の非反転です。最初に望んでいた呼び出しコードに制御を戻します。
You Don't Know JS: Kyle Simpson による非同期とパフォーマンス
developer.mozilla.org
以上がJavaScript コールバックにおける制御の反転: Promise が解決策である理由の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。