関数内で変更した後も変数が変更されない理由 - 非同期コードを理解する
P粉212114661
P粉212114661 2023-10-13 21:51:11
0
2
462

次の例で、outerScopeVarがすべての場合で未定義なのはなぜですか?

リーリー リーリー リーリー リーリー リーリー リーリー リーリー

これらすべての例でunknownが出力されるのはなぜですか?解決策は必要ありません。なぜこれが起こっているのかを知りたいのです。


注:これは JavaScript の非同期性に関する仕様に関する質問です。この質問を自由に改善し、コミュニティが同意できる簡略化された例を追加してください。


P粉212114661
P粉212114661

全員に返信 (2)
P粉930534280

Fabrício の答えは非常に正しいですが、私は、アナロジーを通じて非同期性の概念を説明することに重点を置き、少し専門的ではない内容で彼の答えを補足したいと思います。

###類推...###
昨日、私は同僚から情報を得る必要がある仕事をしていました。彼に電話したところ、会話は次のようになりました:

そう言って電話を切りました。レポートを完成させるためにボブからの情報が必要だったので、私はレポートを離れ、コーヒーを飲みに行き、それからいくつかのメールを読みました。 40 分後 (ボブは遅い) ボブから折り返し電話があり、必要な情報を教えてくれました。この時点で、必要な情報はすべて揃っているので、レポートの作成を続けます。

会話が次のようになったと想像してください;


私はそこに座って待っていました。そして待った。そして待った。 40分。何もせずただ待ってください。結局、ボブが私に情報を提供し、電話を切り、私は報告を終えました。しかし、生産性は 40 分失われました。

これは非同期動作と同期動作の比較です


これはまさに、私たちの質問のすべての例で起こっていることです。画像の読み込み、ディスクからのファイルの読み込み、AJAX 経由でのページのリクエストはすべて (最新のコンピューティングのコンテキストでは) 遅い操作です。

JavaScript を使用すると、

これらの遅い操作が完了するまで待機するのではなく、遅い操作が完了したときに実行されるコールバック関数を登録できます。ただし、その間、JavaScript は他のコードの実行を続けます。遅い操作が完了するのを待っている間に JavaScript が

other code

を実行しているという事実により、動作は非同期になります。 JavaScript が操作の完了を待ってから他のコードを実行する場合、これは同期動作になります。リーリー上記のコードでは、JavaScript にlolcat.pngをロードするように依頼しています。これは

sloooow

操作です。この遅い操作が完了すると、コールバック関数が実行されますが、その間、JavaScript はコードの次の行、つまりalert(outerScopeVar)の処理を続けます。これが、unknownを示すアラートが表示される理由です。これは、

alert()

がイメージのロード後ではなく、すぐに処理されるためです。コードを修正するには、alert(outerScopeVar)コードをコールバック関数に移動するだけです。したがって、

outerScopeVar

変数をグローバル変数として宣言する必要はなくなりました。リーリーコールバックは関数として指定されていることが常に表示されます。これは、JavaScript でコードを定義して後で実行する唯一の方法だからです。

つまり、すべての例で、function() { /* Do Something */ }はコールバックです。すべての例を修正するには、必須 レスポンスを操作するコードはそこに移動されます。

#* 技術的にはeval()も使用できますが、eval()

はその目的にとっては悪です

発信者を保留にするにはどうすればよいですか?現在、これに似たコードがある可能性があります;リーリーただし、

onload
コールバック関数が変数を更新する前に、outerScopeVar

を返す

が即座に行われることがわかりました。これにより、

getWidthOfImage()

unknownを返し、アラートunknownを生成します。

これを修正するには、getWidthOfImage()を呼び出す関数がコールバックを登録し、そのコールバック内に幅アラートを移動できるようにする必要があります。 リーリー

...前と同様に、グローバル変数 (この場合は

width) を削除できたことに注目してください。

いいねを押す+0
    P粉178894235

    一言で答えます:非同期性

    ###序文###

    このトピックは、Stack Overflow で少なくとも何千回も繰り返されています。そこで最初に、非常に役立つリソースをいくつか紹介したいと思います。

    現在の質問への回答

    まず、一般的な動作を追跡しましょう。すべての例で、

    outerScopeVar

    function内で変更されます。この関数は明らかにすぐには実行されず、割り当てられるかパラメータとして渡されます。これをコールバックと呼びます。ここでの問題は、このコールバックがいつ呼び出されるのかということです。

    それは特定の状況によって異なります。もう一度、一般的な動作を追跡してみましょう:

      img.onload
    • (画像が正常に読み込まれた場合)将来のある時点でと呼ばれる可能性があります。
    • setTimeout
    • は、遅延が期限切れになり、タイムアウトがclearTimeoutキャンセルされなかった後、将来の時点で呼び出される可能性があります。注: 遅延として0を使用する場合でも、すべてのブラウザには最小タイムアウト遅延の上限があります (HTML5 仕様では 4 ミリ秒と指定されています)。Ajax リクエストが正常に完了すると、将来のある時点で
    • jQuery のコールバック
    • $.postが呼び出される可能性があります。Node.js のfs.readFile
    • は、
    • 将来、ファイルが正常に読み取られたか、エラーがスローされたときに呼び出される可能性があります。すべての場合において、
    • 将来のある時点で実行される可能性のあるコールバックがあります。この「将来のいつか」を
    非同期ストリーム

    と呼びます。非同期実行は同期プロセスからプッシュされます。つまり、同期コード スタックの実行中、非同期コードは永遠に実行されます。これが JavaScript のシングルスレッドの特徴です。

    より具体的には、JS エンジンがアイドル状態であるとき (大量の同期コードを実行していないとき) は、非同期コールバックをトリガーする可能性のあるイベント (タイムアウト、ネットワーク応答の受信など) をポーリングし、それらを次々に実行します。これはイベント ループとみなされます。

    つまり、赤い手書きの形で強調表示された非同期コードは、それぞれのコード ブロック内の残りの同期コードがすべて実行された後でのみ実行できます。

    つまり、コールバック関数は同期的に作成されますが、実行は非同期的に行われます。非同期関数が実行されたことがわかるまでは、その実行に依存することはできません。どうすればよいでしょうか?

    とても簡単です。非同期関数の実行に依存するロジックは、その非同期関数内から開始/呼び出しする必要があります。たとえば、コールバック関数内で

    alert

    console.log

    を移動すると、その時点で結果が利用できるため、期待どおりの結果が出力されます。

    独自のコールバック ロジックを実装する多くの場合、非同期関数が呼び出される場所に応じて、非同期関数の結果に対してさらに多くの操作を実行したり、結果に対して異なる操作を実行したりする必要があります。より複雑な例を見てみましょう:リーリー

    注:私は、汎用の非同期関数としてランダムな遅延を伴うsetTimeoutを使用しています。同じ例は、Ajax、readFile、onload、およびその他の非同期フローでも機能します。

    この例には明らかに他の例と同じ問題があり、async 関数が実行されるまで待機しません。

    独自のコールバック システムを実装して、この問題を解決しましょう。まず、この場合はまったく役に立たない醜いouterScopeVarを削除します。次に、関数の引数を受け入れるパラメーター、つまりコールバックを追加します。非同期操作が完了すると、このコールバックを呼び出して結果を渡します。実装 (コメントを順番に読んでください):

    リーリー

    上記の例のコード スニペット:

    リーリー
    いいねを押す+0
      最新のダウンロード
      詳細>
      ウェブエフェクト
      公式サイト
      サイト素材
      フロントエンドテンプレート
      私たちについて 免責事項 Sitemap
      PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!