非同期リクエストを行う関数 foo
から応答/結果を返すにはどうすればよいですか?
コールバックから値を返し、その結果を関数内のローカル変数に代入してその変数を返そうとしましたが、これらのメソッドはいずれも実際には応答を返しません。すべて unknown
またはその他のメソッドを返します。その他の変数result
の初期値は次のとおりです。
コールバックを受け入れる非同期関数の例 (jQuery の ajax
関数を使用):
Node.js を使用した例:
リーリーthen
プロミス ブロックを使用した例:
P粉4773692692023-10-09 09:40:11
リーリー
Felix Kling は、AJAX に jQuery を使用する人々向けに素晴らしい回答を書いてくれましたが、私は jQuery を使用しない人々向けに代替案を提供することにしました。 (
新しいfetch API、Angular または Promise を使用している人のために、以下に別の回答を追加しました )
AJAX の
A は、asynchronous を表します。これは、リクエストの送信 (または応答の受信) が通常の実行フローから削除されることを意味します。あなたの例では、.send はすぐに戻り、 code>success
コールバック return result; ## として渡した関数を呼び出す前に次のステートメントが実行されます。 #。
これは、戻ったときに、定義したリスナーがまだ実行されていないこと、つまり、返された値がまだ定義されていないことを意味します。
リーリー ######(バイオリン)######
a=5
部分はまだ実行されていないため、返されるa 値は unknown
です。 AJAX は、サーバーがブラウザに値を伝える前に値を返すように動作します。
この問題に対する考えられる解決策の 1 つは、計算完了後にプログラムに何を行うかを指示するコードを
リアクティブに 記述することです。
リーリー
これは
CPS
getFive に渡し、イベントが完了したときにどのように反応するかをコードに指示します (AJAX 呼び出し、この場合はタイムアウトなど)。
使用方法:
リーリー
「5」が画面に表示されます。 ###(バイオリン)###。
###可能な解決策###
この問題を解決するには、基本的に 2 つの方法があります:
< /p>
AJAX 呼び出しを同期にします (これを SJAX と呼びます)。
コールバックで適切に動作するようにコードをリファクタリングします。 ###1。同期 AJAX - やめてください。 !
Felix の答えは、これがなぜ悪い考えなのかについて、いくつかの説得力のある議論を示しています。全体として、サーバーが応答を返すまでユーザーのブラウザがフリーズし、非常に悪いユーザー エクスペリエンスが作成されます。その理由を説明する MDN の別の短い要約を次に示します。
これをfoo が完了したときに react
を行う方法をコードに伝えます。###それで:### リーリー ###なる:###リーリー
ここでは匿名関数を渡していますが、既存の関数への参照も同じように簡単に渡すことができ、次のようになります。 リーリー
このタイプのコールバック設計を実現する方法の詳細については、Felix の回答を確認してください。次に、対応する操作を実行するために foo 自体を定義しましょう
リーリー ######(バイオリン)######
これで、これをまだ理解できない場合は、MDN の AJAX スタート ガイドを読んでください。
P粉5150665182023-10-09 00:20:22
###質問###
Ajax の A は asynchronous を表します。これは、リクエストの送信 (または応答の受信) が通常の実行フローから削除されることを意味します。あなたの例では、$.ajax はすぐに戻り、success
コールバックとして渡す関数が呼び出される前に、次のステートメント return result;
が実行されます。
これは、同期ストリームと非同期ストリームの違いをより明確にするための例えです:
同期
「通常の」コードを含む関数呼び出しを行う場合にも、同じことが起こります。
リーリー findItem の実行には長い時間がかかる場合がありますが、var item = findItem();
の後のコードは、関数が結果を返すまで 待機する必要があります。
非同期
これはまさに、Ajax リクエストを行うときに起こることです。 リーリー 応答を待たずに、すぐに実行を継続し、Ajax 呼び出しの後にステートメントを実行します。最終的に応答を取得するには、応答の受信後に呼び出される関数、コールバックを提供する必要があります (何かお気づきですか? コールバック?)。この呼び出しの後のステートメントは、コールバックが呼び出される前に実行されます。
###解決###
JavaScript の非同期の性質を活用してください。
一部の非同期操作は (「Ajax」のように) 同期操作を提供しますが、特にブラウザーのコンテキストでは、その使用は一般に推奨されません。JavaScript はブラウザの UI スレッドで実行され、長時間実行されるプロセスによって UI がロックされ、応答しなくなる可能性があります。また、JavaScriptの実行時間には上限があり、ブラウザは実行を継続するかどうかをユーザーに尋ねます。 これらはすべて、非常に悪いユーザー エクスペリエンスにつながる可能性があります。ユーザーは、すべてが適切に動作しているかどうかを判断できません。さらに、インターネット速度が遅いユーザーの場合、影響はさらに大きくなります。
以下では、相互に構築される 3 つの異なるソリューションを紹介します。
async/await
との約束 (ES2017、トランスパイラーまたはリジェネレーターを使用している場合は古いブラウザーで動作します)
Promise と
async/await を使用する
async
と awaitasync/await
Promise に基づいて構築: async
関数は常に Promise を返します。 await
Promise を「ラップ解除」し、解決された Promise の値を生成するか、Promise が拒否された場合はエラーをスローします。
IMPORTANT: await
は、JavaScript モジュール。トップレベルの await
はモジュールの外部ではサポートされていないため、async コンテキスト (モジュールを使用しない場合)。
async と <的更多信息/code>
await について読むことができます。 < MDN 上的 /code>
これは、上記の
関数 findItem() の詳細を示す例です:
リーリー
現在の
および node バージョンは async/await をサポートしています。 regenerator
(または regenerator を使用するツール) を使用してコードを ES5 に変換し、Babel などの古い環境をサポートすることもできます。
質問の例では、
foo にコールバックを受け入れさせ、それを success
コールバックとして使用できます。したがって、この###
リーリー
###なりました###
リーリー
ここでは「インライン」関数を定義しますが、任意の関数参照を渡すことができます:
リーリー
foo
自体は次のように定義されます:リーリー
callback は、呼び出し時に
foo
success に渡します。つまり。 Ajax リクエストが成功すると、
$.ajax は
callback を呼び出し、応答をコールバックに渡します (このように定義しているため、
result で参照できます)コールバック)。
応答をコールバックに渡す前に処理することもできます。
リーリー
コールバックを使用したコードの記述は、見た目よりも簡単です。結局のところ、ブラウザーの JavaScript は主にイベント駆動型 (DOM イベント) です。 Ajax 応答の受信は単なるイベントです。
サードパーティのコードを使用する必要がある場合は問題が発生する可能性がありますが、ほとんどの問題はアプリケーション フローを考えるだけで解決できます。
Promise API は ECMAScript 6 (ES2015) の新しい機能ですが、すでに優れた ブラウザ サポートを備えています。標準の Promises API を実装し、非同期関数の使用と構成を簡素化するための追加メソッドを提供するライブラリも多数あります (例: Bluebird)。
Promise は、将来の 値の コンテナです。 Promise が値を受け取るか (resolved)、またはキャンセルされると (rejected)、その値にアクセスしたいすべての「リスナー」に通知します。 < /p>
通常のコールバックと比較した利点は、コードを分離でき、記述が容易であることです。
これは Promise の使用例です: