Fabrícios Antwort ist genau richtig; aber ich wollte seine Antwort mit etwas weniger Technischem ergänzen, das sich auf eine Analogie konzentriert, um das Konzept der Asynchronität zu erklären .
Eine Analogie ...
Gestern erforderte meine Arbeit einige Informationen von einem Kollegen. Ich habe ihn angerufen; So verlief das Gespräch:
Me : Hallo Bob, ich muss wissen , wie wir foo ‚d der Bar ‘ letzte Woche d. Jim möchte einen Bericht darüber, und Sie sind der einzige, der die Details darüber kennt.
Bob : Sicher, aber ich brauche ungefähr 30 Minuten?
Ich : Das ist großartig, Bob. Rufen Sie mich zurück, wenn Sie die Informationen haben!
Zu diesem Zeitpunkt legte ich auf. Da ich Informationen von Bob brauchte, um meinen Bericht zu vervollständigen, verließ ich den Bericht und ging stattdessen auf einen Kaffee, dann holte ich mir eine E-Mail. 40 Minuten später (Bob ist langsam) rief Bob zurück und gab mir die Informationen, die ich brauchte. Zu diesem Zeitpunkt nahm ich meine Arbeit mit meinem Bericht wieder auf, da ich alle Informationen hatte, die ich brauchte.
Stellen Sie sich vor, das Gespräch wäre stattdessen so verlaufen.
Me : Hallo Bob, ich muss wissen , wie wir foo ‚d der Bar ‘ letzte Woche d. Jim möchte einen Bericht darüber, und Sie sind der einzige, der die Details darüber kennt.
Bob : Sicher, aber ich brauche ungefähr 30 Minuten?
Ich : Das ist großartig, Bob. Ich werde warten.
Und ich saß da und wartete. Und wartete. Und wartete. Für 40 Minuten. Nichts tun als warten. Schließlich gab Bob mir die Informationen, wir legten auf und ich vervollständigte meinen Bericht. Aber ich hatte 40 Minuten Produktivität verloren.
Dies ist asynchrones oder synchrones Verhalten
Genau das passiert in allen Beispielen unserer Frage. Das Laden eines Bildes, das Laden einer Datei von der Festplatte und das Anfordern einer Seite über AJAX sind alles langsame Vorgänge (im Kontext des modernen Rechnens).
Anstatt auf den Abschluss dieser langsamen Vorgänge zu warten , können Sie mit JavaScript eine Rückruffunktion registrieren, die ausgeführt wird, wenn der langsame Vorgang abgeschlossen ist. In der Zwischenzeit wird JavaScript jedoch weiterhin anderen Code ausführen. Die Tatsache, dass JavaScript anderen Code ausführt , während auf den langsamen Vorgang gewartet wird, macht das Verhalten asynchron . Hätte JavaScript gewartet, bis der Vorgang abgeschlossen war, bevor ein anderer Code ausgeführt wurde, wäre dies ein synchrones Verhalten gewesen.
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);
Im obigen Code bitten wir JavaScript zu laden lolcat.png
, was eine langsame Operation ist. Die Rückruffunktion wird ausgeführt, sobald diese langsame Operation ausgeführt wurde. In der Zwischenzeit verarbeitet JavaScript die nächsten Codezeilen weiter. dh alert(outerScopeVar)
.
Aus diesem Grund wird die Warnung angezeigt undefined
. da das alert()
sofort verarbeitet wird, anstatt nachdem das Bild geladen wurde.
Um unseren Code zu beheben, alles , was wir tun müssen , ist die bewegen alert(outerScopeVar)
Code in der Callback - Funktion. Infolgedessen benötigen wir die outerScopeVar
als globale Variable deklarierte Variable nicht mehr .
var img = document.createElement('img');
img.onload = function() {
var localScopeVar = this.width;
alert(localScopeVar);
};
img.src = 'lolcat.png';
Sie werden immer sehen, dass ein Rückruf als Funktion angegeben wird, da dies die einzige * Möglichkeit in JavaScript ist, Code zu definieren, ihn jedoch erst später auszuführen.
Daher ist in allen unseren Beispielen function() { /* Do something */ }
der Rückruf; Um alle Beispiele zu korrigieren , müssen wir nur den Code, der die Antwort der Operation benötigt, dorthin verschieben!
* Technisch können Sie auch verwenden eval()
, ist aber für diesen Zweck eval()
böse
Wie lasse ich meinen Anrufer warten?
Möglicherweise haben Sie derzeit einen ähnlichen Code.
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);
Jetzt wissen wir jedoch, dass return outerScopeVar
dies sofort geschieht. bevor die onload
Rückruffunktion die Variable aktualisiert hat. Dies führt dazu, dass Sie getWidthOfImage()
zurückkehren undefined
und undefined
alarmiert werden.
Um dies zu beheben, müssen wir dem Funktionsaufruf erlauben getWidthOfImage()
, einen Rückruf zu registrieren, und dann die Warnung der Breite so verschieben, dass sie innerhalb dieses Rückrufs liegt.
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);
});
... beachten Sie nach wie vor, dass wir die globalen Variablen (in diesem Fall width
) entfernen konnten .