84669 人が学習中
152542 人が学習中
20005 人が学習中
5487 人が学習中
7821 人が学習中
359900 人が学習中
3350 人が学習中
180660 人が学習中
48569 人が学習中
18603 人が学習中
40936 人が学習中
1549 人が学習中
1183 人が学習中
32909 人が学習中
次の例で、outerScopeVarがすべての場合で未定義なのはなぜですか?
outerScopeVar
これらすべての例でunknownが出力されるのはなぜですか?解決策は必要ありません。なぜこれが起こっているのかを知りたいのです。
unknown
注:これは JavaScript の非同期性に関する仕様に関する質問です。この質問を自由に改善し、コミュニティが同意できる簡略化された例を追加してください。
Fabrício の答えは非常に正しいですが、私は、アナロジーを通じて非同期性の概念を説明することに重点を置き、少し専門的ではない内容で彼の答えを補足したいと思います。
会話が次のようになったと想像してください;
これは非同期動作と同期動作の比較です
これらの遅い操作が完了するまで待機するのではなく、遅い操作が完了したときに実行されるコールバック関数を登録できます。ただし、その間、JavaScript は他のコードの実行を続けます。遅い操作が完了するのを待っている間に JavaScript が
を実行しているという事実により、動作は非同期になります。 JavaScript が操作の完了を待ってから他のコードを実行する場合、これは同期動作になります。リーリー上記のコードでは、JavaScript にlolcat.pngをロードするように依頼しています。これは
操作です。この遅い操作が完了すると、コールバック関数が実行されますが、その間、JavaScript はコードの次の行、つまりalert(outerScopeVar)の処理を続けます。これが、unknownを示すアラートが表示される理由です。これは、
alert(outerScopeVar)
がイメージのロード後ではなく、すぐに処理されるためです。コードを修正するには、alert(outerScopeVar)コードをコールバック関数に移動するだけです。したがって、
変数をグローバル変数として宣言する必要はなくなりました。リーリーコールバックは関数として指定されていることが常に表示されます。これは、JavaScript でコードを定義して後で実行する唯一の方法だからです。
リーリー
つまり、すべての例で、function() { /* Do Something */ }はコールバックです。すべての例を修正するには、必須 レスポンスを操作するコードはそこに移動されます。
#* 技術的にはeval()も使用できますが、eval()
eval()
発信者を保留にするにはどうすればよいですか?現在、これに似たコードがある可能性があります;リーリーただし、
getWidthOfImage()
unknownを返し、アラートunknownを生成します。
を返し、アラート
を生成します。
これを修正するには、getWidthOfImage()を呼び出す関数がコールバックを登録し、そのコールバック内に幅アラートを移動できるようにする必要があります。 リーリー
width) を削除できたことに注目してください。
) を削除できたことに注目してください。
一言で答えます:非同期性。
。同期プロセスと非同期プロセスを説明した彼の優れた回答と、「コードの再編成」セクションを参照してください。@Benjamin Gruenbaum は、同じスレッド内の非同期性の説明にも多大な労力を費やしました。
も、非同期性を簡単な方法で説明するのに適しています。
はfunction内で変更されます。この関数は明らかにすぐには実行されず、割り当てられるかパラメータとして渡されます。これをコールバックと呼びます。ここでの問題は、このコールバックがいつ呼び出されるのかということです。
function
それは特定の状況によって異なります。もう一度、一般的な動作を追跡してみましょう:
将来のある時点で
clearTimeout
時点で呼び出される可能性があります。注: 遅延として
Ajax リクエストが正常に完了すると、
Node.js の
呼び出される可能性があります。
と呼びます。非同期実行は同期プロセスからプッシュされます。つまり、同期コード スタックの実行中、非同期コードは永遠に実行されます。これが JavaScript のシングルスレッドの特徴です。
より具体的には、JS エンジンがアイドル状態であるとき (大量の同期コードを実行していないとき) は、非同期コールバックをトリガーする可能性のあるイベント (タイムアウト、ネットワーク応答の受信など) をポーリングし、それらを次々に実行します。これはイベント ループとみなされます。
つまり、赤い手書きの形で強調表示された非同期コードは、それぞれのコード ブロック内の残りの同期コードがすべて実行された後でのみ実行できます。
alert
console.log
独自のコールバック ロジックを実装する多くの場合、非同期関数が呼び出される場所に応じて、非同期関数の結果に対してさらに多くの操作を実行したり、結果に対して異なる操作を実行したりする必要があります。より複雑な例を見てみましょう:リーリー
独自のコールバック ロジックを実装する
多くの場合、非同期関数が呼び出される場所に応じて、非同期関数の結果に対してさらに多くの操作を実行したり、結果に対して異なる操作を実行したりする必要があります。より複雑な例を見てみましょう:
注:私は、汎用の非同期関数としてランダムな遅延を伴うsetTimeoutを使用しています。同じ例は、Ajax、readFile、onload、およびその他の非同期フローでも機能します。
setTimeout
この例には明らかに他の例と同じ問題があり、async 関数が実行されるまで待機しません。
独自のコールバック システムを実装して、この問題を解決しましょう。まず、この場合はまったく役に立たない醜いouterScopeVarを削除します。次に、関数の引数を受け入れるパラメーター、つまりコールバックを追加します。非同期操作が完了すると、このコールバックを呼び出して結果を渡します。実装 (コメントを順番に読んでください):
上記の例のコード スニペット:
Fabrício の答えは非常に正しいですが、私は、アナロジーを通じて非同期性の概念を説明することに重点を置き、少し専門的ではない内容で彼の答えを補足したいと思います。
###類推...###昨日、私は同僚から情報を得る必要がある仕事をしていました。彼に電話したところ、会話は次のようになりました: そう言って電話を切りました。レポートを完成させるためにボブからの情報が必要だったので、私はレポートを離れ、コーヒーを飲みに行き、それからいくつかのメールを読みました。 40 分後 (ボブは遅い) ボブから折り返し電話があり、必要な情報を教えてくれました。この時点で、必要な情報はすべて揃っているので、レポートの作成を続けます。
会話が次のようになったと想像してください;
私はそこに座って待っていました。そして待った。そして待った。 40分。何もせずただ待ってください。結局、ボブが私に情報を提供し、電話を切り、私は報告を終えました。しかし、生産性は 40 分失われました。
これは非同期動作と同期動作の比較です
これはまさに、私たちの質問のすべての例で起こっていることです。画像の読み込み、ディスクからのファイルの読み込み、AJAX 経由でのページのリクエストはすべて (最新のコンピューティングのコンテキストでは) 遅い操作です。 JavaScript を使用すると、
これらの遅い操作が完了するまで待機するのではなく、遅い操作が完了したときに実行されるコールバック関数を登録できます。ただし、その間、JavaScript は他のコードの実行を続けます。遅い操作が完了するのを待っている間に JavaScript が
other codeを実行しているという事実により、動作は非同期になります。 JavaScript が操作の完了を待ってから他のコードを実行する場合、これは同期動作になります。リーリー上記のコードでは、JavaScript にlolcat.pngをロードするように依頼しています。これは
sloooow操作です。この遅い操作が完了すると、コールバック関数が実行されますが、その間、JavaScript はコードの次の行、つまり
alert()alert(outerScopeVar)
の処理を続けます。これが、unknown
を示すアラートが表示される理由です。これは、がイメージのロード後ではなく、すぐに処理されるためです。
outerScopeVarコードを修正するには、
alert(outerScopeVar)
コードをコールバック関数に移動するだけです。したがって、変数をグローバル変数として宣言する必要はなくなりました。
リーリー
コールバックは関数として指定されていることが常に表示されます。これは、JavaScript でコードを定義して後で実行する唯一の方法だからです。
つまり、すべての例で、function() { /* Do Something */ }はコールバックです。すべての例を修正するには、必須 レスポンスを操作するコードはそこに移動されます。
#* 技術的には
はその目的にとっては悪ですeval()
も使用できますが、eval()
onload発信者を保留にするにはどうすればよいですか?
現在、これに似たコードがある可能性があります;リーリーただし、
コールバック関数が変数を更新する前に、outerScopeVar
を返す
が即座に行われることがわかりました。これにより、getWidthOfImage()
はunknown
を返し、アラート
unknownを生成します。
これを修正するには、
...前と同様に、グローバル変数 (この場合はgetWidthOfImage()
を呼び出す関数がコールバックを登録し、そのコールバック内に幅アラートを移動できるようにする必要があります。 リーリーwidth
) を削除できたことに注目してください。
一言で答えます:非同期性。
###序文###このトピックは、Stack Overflow で少なくとも何千回も繰り返されています。そこで最初に、非常に役立つリソースをいくつか紹介したいと思います。
。同期プロセスと非同期プロセスを説明した彼の優れた回答と、「コードの再編成」セクションを参照してください。@Benjamin Gruenbaum は、同じスレッド内の非同期性の説明にも多大な労力を費やしました。
も、非同期性を簡単な方法で説明するのに適しています。
まず、一般的な動作を追跡しましょう。すべての例で、
outerScopeVarは
function
内で変更されます。この関数は明らかにすぐには実行されず、割り当てられるかパラメータとして渡されます。これをコールバックと呼びます。ここでの問題は、このコールバックがいつ呼び出されるのかということです。それは特定の状況によって異なります。もう一度、一般的な動作を追跡してみましょう:
img.onload- (画像が正常に読み込まれた場合)
setTimeout
- は、遅延が期限切れになり、タイムアウトが
jQuery のコールバック
- $.postが呼び出される可能性があります。
は、
- 将来、ファイルが正常に読み取られたか、エラーがスローされたときに
将来のある時点で実行される可能性のあるコールバックがあります。この「将来のいつか」を
非同期ストリーム将来のある時点で
と呼ばれる可能性があります。clearTimeout
キャンセルされなかった後、将来の時点で呼び出される可能性があります。注: 遅延として
0を使用する場合でも、すべてのブラウザには最小タイムアウト遅延の上限があります (HTML5 仕様では 4 ミリ秒と指定されています)。Ajax リクエストが正常に完了すると、
将来のある時点でNode.js の
fs.readFile呼び出される可能性があります。
すべての場合において、と呼びます。非同期実行は同期プロセスからプッシュされます。つまり、同期コード スタックの実行中、非同期コードは永遠に実行されます。これが JavaScript のシングルスレッドの特徴です。
より具体的には、JS エンジンがアイドル状態であるとき (大量の同期コードを実行していないとき) は、非同期コールバックをトリガーする可能性のあるイベント (タイムアウト、ネットワーク応答の受信など) をポーリングし、それらを次々に実行します。これはイベント ループとみなされます。
つまり、赤い手書きの形で強調表示された非同期コードは、それぞれのコード ブロック内の残りの同期コードがすべて実行された後でのみ実行できます。
つまり、コールバック関数は同期的に作成されますが、実行は非同期的に行われます。非同期関数が実行されたことがわかるまでは、その実行に依存することはできません。どうすればよいでしょうか? とても簡単です。非同期関数の実行に依存するロジックは、その非同期関数内から開始/呼び出しする必要があります。たとえば、コールバック関数内でalert
とconsole.log
を移動すると、その時点で結果が利用できるため、期待どおりの結果が出力されます。独自のコールバック ロジックを実装する
多くの場合、非同期関数が呼び出される場所に応じて、非同期関数の結果に対してさらに多くの操作を実行したり、結果に対して異なる操作を実行したりする必要があります。より複雑な例を見てみましょう:
リーリー注:私は、汎用の非同期関数としてランダムな遅延を伴う
setTimeout
を使用しています。同じ例は、Ajax、readFile、onload、およびその他の非同期フローでも機能します。この例には明らかに他の例と同じ問題があり、async 関数が実行されるまで待機しません。
独自のコールバック システムを実装して、この問題を解決しましょう。まず、この場合はまったく役に立たない醜い
リーリーouterScopeVar
を削除します。次に、関数の引数を受け入れるパラメーター、つまりコールバックを追加します。非同期操作が完了すると、このコールバックを呼び出して結果を渡します。実装 (コメントを順番に読んでください):上記の例のコード スニペット: