ファブリシオの答えはまさにスポットライトです。しかし、私は彼の答えをより技術的でないもので補完したかったのです。
アナロジー...
昨日、私が行っていた仕事には同僚からの情報が必要でした。彼に電話した。会話は次のとおりです。
私:こんにちはボブは、私たちはどのように知っている必要がありますfooの「D バーを先週D」。ジムはそれについての報告を望んでおり、あなたはそれについての詳細を知っている唯一の人です。
ボブ:確かに、でも30分くらいかかる?
私:それは素晴らしいボブです。情報が得られたら、リングを返してください!
この時点で、電話を切った。レポートを完成させるにはボブからの情報が必要だったので、レポートを残して代わりにコーヒーを飲みに行き、メールを受け取りました。40分後(ボブは遅い)、ボブは電話をかけ直し、必要な情報を教えてくれました。この時点で、必要な情報がすべて揃っていたので、レポートで作業を再開しました。
代わりに会話がこのようになったと想像してください。
私:こんにちはボブは、私たちはどのように知っている必要がありますfooの「D バーを先週D」。ジムはそれについてのレポートを望んでおり、あなたはそれについての詳細を知っている唯一の人です。
ボブ:確かに、でも30分くらいかかる?
私:それは素晴らしいボブです。待ちます。
そして、私はそこに座って待っていました。そして待った。そして待った。40分間。待っている以外は何もしません。最終的に、ボブは私に情報を提供し、電話を切り、レポートを完成させました。しかし、40分の生産性が失われました。
これは非同期動作と同期動作です
これが、質問のすべての例で起こっていることです。イメージのロード、ディスクからのファイルのロード、およびAJAXを介したページのリクエストは、すべて遅い操作です(最新のコンピューティングのコンテキストで)。
JavaScriptでは、これらの遅い操作が完了するのを待つのではなく、遅い操作が完了したときに実行されるコールバック関数を登録できます。ただし、その間、JavaScriptは引き続き他のコードを実行します。遅い操作が完了するのを待っている間にJavaScriptが他のコードを実行するという事実は、動作を非同期にします。JavaScriptが他のコードを実行する前に操作の完了を待機していた場合、これは同期的な動作でした。
var outerScopeVar;
var img = document.createElement('img');
// Here we register the callback function.
img.onload = function() {
// Code within this function will be executed once the image has loaded.
outerScopeVar = this.width;
};
// But, while the image is loading, JavaScript continues executing, and
// processes the following lines of JavaScript.
img.src = 'lolcat.png';
alert(outerScopeVar);
上記のコードlolcat.png
では、JavaScriptにloadを要求していますが、これはsloooow操作です。この遅い操作が完了すると、コールバック関数が実行されますが、その間、JavaScriptは次のコード行の処理を続けます。すなわちalert(outerScopeVar)
。
これが、アラートが表示される理由undefined
です。以来、alert()
すぐに処理されるのではなく、イメージがロードされた後。
コードを修正するには、alert(outerScopeVar)
コードをコールバック関数に移動するだけです。この結果outerScopeVar
、グローバル変数として宣言された変数は必要なくなりました。
var img = document.createElement('img');
img.onload = function() {
var localScopeVar = this.width;
alert(localScopeVar);
};
img.src = 'lolcat.png';
コールバックは関数として指定されていることが常にわかります。これは、JavaScriptでコードを定義する唯一の方法であるが、後まで実行しないためです。
したがって、すべての例で、function() { /* Do something */ }
はコールバックです。すべての例を修正するには、操作の応答を必要とするコードをそこに移動するだけです!
*技術的にはeval()
同様に使用できますが、この目的にeval()
は悪です
発信者を待機させるにはどうすればよいですか?
現在、これに似たコードがあるかもしれません。
function getWidthOfImage(src) {
var outerScopeVar;
var img = document.createElement('img');
img.onload = function() {
outerScopeVar = this.width;
};
img.src = src;
return outerScopeVar;
}
var width = getWidthOfImage('lolcat.png');
alert(width);
ただし、return outerScopeVar
すぐに発生することがわかっています。onload
コールバック関数が変数を更新する前。これにより、にgetWidthOfImage()
戻りundefined
、undefined
アラートが発生します。
これを修正するにはgetWidthOfImage()
、コールバックを登録する関数呼び出しを許可し、そのコールバック内に幅のアラートを移動する必要があります。
function getWidthOfImage(src, cb) {
var img = document.createElement('img');
img.onload = function() {
cb(this.width);
};
img.src = src;
}
getWidthOfImage('lolcat.png', function (width) {
alert(width);
});
...前と同様に、グローバル変数(この場合width
)を削除できたことに注意してください。