非同期呼び出しから応答を返すにはどうすればよいですか?
P粉668113768
P粉668113768 2023-08-23 12:49:32
0
2
601
<p>非同期リクエストを行う関数 <code>foo</code> から応答/結果を返すにはどうすればよいですか? </p> <p>コールバックから値を返し、その結果を関数内のローカル変数に代入してその変数を返そうとしましたが、これらのメソッドはいずれも実際には応答を返しません。すべて <code>unknown< /code> を返します。または変数 result の初期値。 </code></p><code> <p><strong>コールバックを受け入れる非同期関数の例</strong> (jQuery の <code>ajax</code> 関数を使用): </p> <pre class="brush:php;toolbar:false;">function foo() { var 結果; $.ajax({ URL: '...'、 成功: 関数(応答) { 結果 = 応答; // 応答を返す; // <- それも試してみました } }); return result; // 常に `unknown` を返します }</pre> <p><strong>Node.js を使用した例:</strong></p> <pre class="brush:php;toolbar:false;">function foo() { var 結果; fs.readFile("パス/ファイルへ", function(err, data) { 結果 = データ; // return data; // <- それも試してみました }); return result; // 常に `unknown` を返します }</pre> <p><strong>Promise を使用した <code>then</code> ブロックの例: </strong></p> <pre class="brush:php;toolbar:false;">function foo() { var 結果; fetch(url).then(function(response) { 結果 = 応答; // 応答を返す; // <- それも試してみました }); return result; // 常に `unknown` を返します }</pre> <p><br /></p></code>
P粉668113768
P粉668113768

全員に返信(2)
P粉334721359

コードで jQuery を 使用しない場合は、この回答が役に立ちます

コードは次のようになります:

リーリー

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 つの方法があります:

AJAX 呼び出しを同期にします (これを SJAX と呼びます)。

コールバックで適切に動作するようにコードをリファクタリングします。 ###1。同期 AJAX - やめてください。 !

同期 AJAX に関しては、

やめてください。

Felix の答えは、これがなぜ悪い考えなのかについて、いくつかの説得力のある議論を示しています。全体として、サーバーが応答を返すまでユーザーのブラウザがフリーズし、非常に悪いユーザー エクスペリエンスが作成されます。その理由を説明する MDN の別の短い要約を次に示します。

これを
    行う必要がある場合は、フラグを渡すことができます。
  1. 具体的な方法は以下の通りです
  2. :
  3. リーリー ###2。組織再編コード
関数がコールバックを受け入れるようにします。コード例では、

foo

がコールバックを受け入れるようにできます。

foo が完了したときに react

を行う方法をコードに伝えます。

###それで:### リーリー ###なる:###リーリー

ここでは匿名関数を渡していますが、既存の関数への参照も同じように簡単に渡すことができ、次のようになります。 リーリー

このタイプのコールバック設計を実現する方法の詳細については、Felix の回答を確認してください。

次に、対応する操作を実行するために foo 自体を定義しましょう

リーリー ######(バイオリン)######

これで、

foo 関数が、AJAX が正常に完了したときに実行するアクションを受け入れるようになりました。応答ステータスが 200 でないことを確認し、適切なアクション (失敗ハンドラーの作成など) を実行することで、この機能をさらに拡張できます。それは私たちの問題を効果的に解決しました。

これをまだ理解できない場合は、

MDN の AJAX スタート ガイドを読んでください。

いいねを押す +0
P粉642920522

###質問###

Ajax

Aasynchronous を表します。これは、リクエストの送信 (または応答の受信) が通常の実行フローから削除されることを意味します。あなたの例では、$.ajax はすぐに戻り、success コールバックとして渡す関数が呼び出される前に、次のステートメント return result; が実行されます。 これは、同期ストリームと非同期ストリームの違いをより明確にするための例えです:

同期

あなたが友人に電話して、何か情報を見つけてもらうように頼んだと想像してください。時間はかかるかもしれませんが、友人が必要な答えをくれるまで、電話のそばで宇宙を見つめながら待ちます。

「通常の」コードを含む関数呼び出しを行う場合にも、同じことが起こります。

リーリー

findItem

の実行には長い時間がかかる場合がありますが、var item = findItem(); の後のコードは、関数が結果を返すまで 待機する必要があります。 非同期

あなたはまた同じ理由で友達に電話をかけます。しかし、今回はあなたが不安なので、携帯電話

に折り返し電話してくださいと伝えます。電話を切り、家を出て、予定していたすべてのことを行います。友人があなたに折り返し電話をかけてきたら、あなたは彼があなたにくれた情報を処理していることになります。

これはまさに、Ajax リクエストを行うときに起こることです。 リーリー 応答を待たずに、すぐに実行を継続し、Ajax 呼び出しの後にステートメントを実行します。最終的に応答を取得するには、応答の受信後に呼び出される関数、コールバックを提供する必要があります (何かお気づきですか? コールバック?)。この呼び出しの後のステートメントは、コールバックが呼び出される前に実行されます。

###解決###

JavaScript の非同期の性質を活用してください。

一部の非同期操作は (「Ajax」のように) 同期操作を提供しますが、特にブラウザーのコンテキストでは、その使用は一般に推奨されません。

なぜそれが悪いのですか?

JavaScript はブラウザの UI スレッドで実行され、長時間実行されるプロセスによって UI がロックされ、応答しなくなる可能性があります。また、JavaScriptの実行時間には上限があり、ブラウザは実行を継続するかどうかをユーザーに尋ねます。 これらはすべて、非常に悪いユーザー エクスペリエンスにつながる可能性があります。ユーザーは、すべてが適切に動作しているかどうかを判断できません。さらに、インターネット速度が遅いユーザーの場合、影響はさらに大きくなります。

以下では、相互に構築される 3 つの異なるソリューションを紹介します。

async/await

との約束 (ES2017、トランスパイラーまたはリジェネレーターを使用している場合は古いブラウザーで動作します)

  • コールバック (ノードで人気) Promise と
  • then()
  • (ES2015、多くの Promise ライブラリのいずれかを使用している場合は古いブラウザでも動作します)
  • 3 つの機能はすべて、現在のブラウザと Node 7 で使用できます。
  • ES2017: プロミスに

async/await を使用する


ECMAScript の 2017 リリースでは、非同期関数の

構文レベルのサポートが導入されました。 asyncawait

を使用すると、「同期スタイル」で非同期に書くことができます。コードは依然として非同期ですが、読みやすく理解しやすくなっています。

async/await Promise に基づいて構築: async 関数は常に Promise を返します。 await Promise を「ラップ解除」し、解決された Promise の値を生成するか、Promise が拒否された場合はエラーをスローします。

IMPORTANT: await は、JavaScript モジュール。トップレベルの await はモジュールの外部ではサポートされていないため、async コンテキスト (モジュールを使用しない場合)。

asyncawait について読むことができます。 これは、上記の

遅延

関数 findItem() の詳細を示す例です: リーリー 現在の

ブラウザ

および node バージョンは async/await をサポートしています。 regenerator (または regenerator を使用するツール) を使用してコードを ES5 に変換し、Babel などの古い環境をサポートすることもできます。

関数にコールバックを受け入れさせます

コールバックは、関数 1 が関数 2 に渡されるときを指します。関数 2 は、準備ができたら関数 1 を呼び出すことができます。非同期プロセスのコンテキストでは、非同期プロセスが完了するたびにコールバックが呼び出されます。通常、結果はコールバックに渡されます。

質問の例では、

foo

にコールバックを受け入れさせ、それを success コールバックとして使用できます。したがって、この### リーリー ###なりました### リーリー ここでは「インライン」関数を定義しますが、任意の関数参照を渡すことができます: リーリー

foo

自体は次のように定義されます:

リーリー

callback は、呼び出し時に foo

に渡した関数を参照し、それを

success に渡します。つまり。 Ajax リクエストが成功すると、$.ajaxcallback を呼び出し、応答をコールバックに渡します (このように定義しているため、result で参照できます)コールバック)。 応答をコールバックに渡す前に処理することもできます。 リーリー コールバックを使用したコードの記述は、見た目よりも簡単です。結局のところ、ブラウザーの JavaScript は主にイベント駆動型 (DOM イベント) です。 Ajax 応答の受信は単なるイベントです。 サードパーティのコードを使用する必要がある場合は問題が発生する可能性がありますが、ほとんどの問題はアプリケーション フローを考えるだけで解決できます。


ES2015: then()的 Promise >

を使用

Promise API は ECMAScript 6 (ES2015) の新しい機能ですが、すでに優れた ブラウザ サポートを備えています。標準の Promises API を実装し、非同期関数の使用と構成を簡素化するための追加メソッドを提供するライブラリも多数あります (例: Bluebird)。

Promise は、将来の 値の コンテナです。 Promise が値を受け取るか (resolved)、またはキャンセルされると (rejected)、その値にアクセスしたいすべての「リスナー」に通知します。

通常のコールバックと比較した利点は、コードを分離でき、記述が容易であることです。

これは Promise の使用例です:

リーリー リーリー
いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート