問題 Ajax アプリケーションでは、XMLHttpRequest の呼び出しは非常に一般的な状況です。特にクライアント中心の Ajax アプリケーションの場合、サーバーからデータを取得する必要があるさまざまな操作は、XHR 非同期呼び出しを通じて完了します。ただし、シングルスレッド JavaScript プログラミングでは、XHR 非同期呼び出しのコード スタイルは、一般的な JavaScript コードと互換性がありません。
追加パラメータ 純粋なクライアント側の同期関数の場合、シグネチャは次のようになります。
function dive(operand1) , operand2 )
ただし、クライアント側の除算の精度に満足できないため、実行のために除算をサーバー側に転送するとします。その場合、これは XHR を呼び出す必要がある非同期関数になります。署名は次のいずれかです:
関数分割(オペランド1, オペランド2, コールバック)
関数分割(オペランド1, オペランド2, successCallback, FailureCallback)
関数分割(オペランド1, オペランド2, オプション)
コールバック関数を渡すには、シグネチャに新しいパラメーターを導入する必要があります。関数をブロッキング同期呼び出しにするオプションはありません。
移植性
XHR を直接操作する関数は新しいパラメーターを導入する必要があるだけでなく、この複雑さは呼び出しスタックにも渡されます。たとえば、加算、減算、乗算、除算の 4 つの算術演算をカプセル化し、次の 1 つの演算インターフェイスのみを公開しました。演算子パラメータに基づいて、内部の加算、減算、乗算、除算関数を呼び出します。ただし、除算関数は非同期関数になるため、計算関数全体を非同期関数に変換する必要があります。
function Calculate(operand1, operand2, Operand2, callback)
同時に呼び出し時の時間 計算のために呼び出す必要があるスタック上の関数は、上位レベルの呼び出し関数から結果を返す必要がない場合を除き、非同期にする必要があります。
同期共存
calculate 関数は非同期関数になりますが、呼び出される加算、減算、乗算関数は、divide が呼び出されたときのみ非同期関数になります。非同期同期関数です。
これによりどのような問題が発生しますか? Calculate の呼び出し元は、この関数シグネチャを見ると、コールバック関数を渡す必要があるため、Calculate が非同期関数であると自然に考えるでしょう。しかし、calculate の実行方法は不明です。次の呼び出しを考えてみましょう:
calculate(operand1, operand2, operand2, operands, callback);
next();
これには、callback と next の 2 つの関数が含まれており、どちらが最初に実行されます。どちらが最後に実行されるか 実行は不確実であるか、または Calculate の特定の実装に依存します。
calculate の実装の場合、非同期操作が必要ない場合は、コールバックが直接呼び出されます。次に、加算、減算、乗算を実行する場合は next の前にコールバックが呼び出され、除算を実行する場合はコールバックよりも前に next が呼び出されます。
この不確実性が気に入らない場合は、calculate の実装を変更し、すべての同期呼び出しを setTimeout 形式に変更して、どのような状況でもコールバックの前に next が確実に呼び出されるようにすることができます。
ただし、後者のアプローチは高コストの実装に依存しており、開発者が誤って setTimeout を見逃して (または単なる怠惰なだけで)、関数の呼び出しシーケンスが不確実になる可能性があるため、これは関数です。フレームワークはそれを達成するのに役立ちますが、フレームワークを使用する場合にはそれを回避する方法はありません。
シナリオ
ここでは、上記の問題に関する具体的な応用シナリオを示します。 (問題を単純化するために、説明は少し変更されていますが、実際のアプリケーションとは一致しません。)
Baidu Hi Web バージョンでは、クライアントにユーザー オブジェクトのリストを保存し、このユーザーとのチャット ウィンドウ いつ、そこからこのユーザーの情報を読み取る必要があります。この操作には、同期または非同期の多くの分岐が含まれます:
ユーザー オブジェクトはキャッシュされません
ユーザー情報を非同期で読み取ります
ユーザー オブジェクトはキャッシュされます
ユーザーは友達です (情報は更新されます)サーバークライアントプッシュによって更新されます)
ユーザー情報を同期的に読み取ります
ユーザーは友達ではありません (情報の更新はクライアントから取得する必要があります)
キャッシュ情報を受け入れることができます
ユーザー情報を読み取ります同期
最新の情報を取得する必要がある
ユーザー情報を非同期で読み取る
分岐の結果が同期と非同期の両方であることがわかります。そして、これらの分岐は 1 つの関数で完了するのではなく、複数の関数で完了します。つまり、従来のモデルによれば、これらの関数の一部は同期であり、一部は非同期です。非同期の推移性により、最終的な呼び出しスタックの最上位にある関数はすべて非同期になります。
この問題を解決するには、非同期呼び出しフレームワークを作成し、統一された方法で呼び出しを行い、同期呼び出しと非同期呼び出しを 1 つの return メソッドに結合する必要があります。