Synchrone und asynchrone Anfragen
XMLHttpRequest
unterstützt sowohl synchrone als auch asynchrone Kommunikation. Im Allgemeinen sollten jedoch aus Leistungsgründen asynchrone Anfragen gegenüber synchronen bevorzugt werden.
Synchrone Anfragen blockieren die Ausführung von Code, was ein "Einfrieren" des Bildschirms und eine nicht reagierende Benutzererfahrung verursacht.
Asynchrone Anfrage
Wenn Sie ein asynchrones XMLHttpRequest
verwenden, erhalten Sie einen Rückruf, wenn die Daten empfangen wurden. Dies ermöglicht es dem Browser, normal weiterzuarbeiten, während Ihre Anfrage bearbeitet wird.
Beispiel: Eine Datei an die Konsolenprotokollierung senden
Dies ist die einfachste Verwendung von asynchronem XMLHttpRequest
.
const xhr = new XMLHttpRequest();
xhr.open("GET", "/bar/foo.txt", true);
xhr.onload = (e) => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.error(xhr.statusText);
}
}
};
xhr.onerror = (e) => {
console.error(xhr.statusText);
};
xhr.send(null);
Die xhr.open
-Zeile gibt true
als dritten Parameter an, um anzuzeigen, dass die Anfrage asynchron behandelt werden soll.
Wir erstellen dann ein Event-Handler-Funktionsobjekt und weisen es dem onload
-Attribut der Anfrage zu. Dieser Handler prüft den readyState
der Anfrage, um festzustellen, ob die Transaktion abgeschlossen ist; wenn dies der Fall ist und der HTTP-Status 200 beträgt, wird der empfangene Inhalt ausgegeben. Wenn ein Fehler aufgetreten ist, wird eine Fehlermeldung angezeigt.
Der xhr.send
-Aufruf startet tatsächlich die Anfrage. Die Rückrufroutine wird aufgerufen, wenn sich der Status der Anfrage ändert.
Beispiel: Eine Funktion zum Lesen einer externen Datei schreiben
In einigen Fällen müssen Sie viele externe Dateien lesen. Dies ist eine Standardfunktion, die das XMLHttpRequest
-Objekt asynchron verwendet, um den Inhalt der gelesenen Datei an einen angegebenen Listener zu übergeben.
function xhrSuccess() {
this.callback.apply(this, this.arguments);
}
function xhrError() {
console.error(this.statusText);
}
function loadFile(url, callback, ...args) {
const xhr = new XMLHttpRequest();
xhr.callback = callback;
xhr.arguments = args;
xhr.onload = xhrSuccess;
xhr.onerror = xhrError;
xhr.open("GET", url, true);
xhr.send(null);
}
Verwendung:
function showMessage(message) {
console.log(`${message} ${this.responseText}`);
}
loadFile("message.txt", showMessage, "New message!\n\n");
Die Signatur der Dienstprogrammfunktion loadFile erklärt (i) eine Ziel-URL, die gelesen werden soll (über eine HTTP-GET-Anfrage), (ii) eine Funktion, die bei erfolgreichem Abschluss der XHR-Operation ausgeführt werden soll, und (iii) eine beliebige Liste zusätzlicher Argumente, die über das XHR-Objekt (über die arguments
-Eigenschaft) an die Erfolgs-Rückruffunktion übergeben werden.
Wir deklarieren zuerst eine Funktion xhrSuccess
, die aufgerufen wird, wenn die XHR-Operation erfolgreich abgeschlossen ist. Diese wiederum ruft die Rückruffunktion auf, die bei der Verwendung der Funktion loadFile
(in diesem Fall die Funktion showMessage
) angegeben wurde, und die einem Attribut des XHR-Objekts zugewiesen wurde. Die zusätzlichen Argumente (falls vorhanden), die bei der Verwendung der Funktion loadFile übergeben wurden, werden zur Ausführung der Rückruffunktion "angewendet". Die xhrError
-Funktion wird aufgerufen, wenn die XHR-Operation nicht erfolgreich abgeschlossen werden kann.
Wir speichern den Erfolgs-Rückruf, der als zweites Argument an loadFile
übergeben wird, in der callback
-Eigenschaft des XHR-Objekts. Beginnend mit dem dritten Argument werden alle verbleibenden Argumente von loadFile
gesammelt (mithilfe der Rest-Parameter-Syntax), der arguments
-Eigenschaft der Variablen xhr
zugewiesen, an die Erfolgs-Rückruffunktion xhrSuccess
übergeben und letztendlich der Rückruffunktion bereitgestellt (in diesem Fall showMessage
), die durch die Funktion xhrSuccess
aufgerufen wird.
Der xhr.open
-Aufruf gibt true
als dritten Parameter an, um anzuzeigen, dass die Anfrage asynchron behandelt werden soll.
Schließlich startet xhr.send
tatsächlich die Anfrage.
Beispiel: Verwendung eines Timeouts
Sie können ein Timeout verwenden, um zu verhindern, dass Ihr Code hängt, während er auf den Abschluss eines Lesevorgangs wartet. Dies wird erreicht, indem der Wert der timeout
-Eigenschaft des XMLHttpRequest
-Objekts gesetzt wird, wie im folgenden Code gezeigt:
function loadFile(url, timeout, callback, ...args) {
const xhr = new XMLHttpRequest();
xhr.ontimeout = () => {
console.error(`The request for ${url} timed out.`);
};
xhr.onload = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
callback.apply(xhr, args);
} else {
console.error(xhr.statusText);
}
}
};
xhr.open("GET", url, true);
xhr.timeout = timeout;
xhr.send(null);
}
Beachten Sie die Hinzufügung von Code, um das "timeout"-Ereignis zu behandeln, indem der ontimeout
-Handler gesetzt wird.
Verwendung:
function showMessage(message) {
console.log(`${message} ${this.responseText}`);
}
loadFile("message.txt", 2000, showMessage, "New message!\n");
Hier geben wir ein Timeout von 2000 ms an.
Synchrone Anfrage
Warnung: Synchrone XHR-Anfragen verursachen oft Probleme im Web, insbesondere bei schlechten Netzwerkbedingungen oder wenn der entfernte Server langsam reagiert. Synchronous XHR ist jetzt veraltet und sollte zugunsten asynchroner Anfragen vermieden werden.
Alle neuen XHR-Funktionen wie timeout
oder abort
sind für synchrone XHR nicht erlaubt. Bei Verwendung wird ein InvalidAccessError
ausgelöst.
Beispiel: HTTP-synchrone Anfrage
Dieses Beispiel demonstriert, wie man eine einfache synchrone Anfrage durchführt.
const request = new XMLHttpRequest();
request.open("GET", "/bar/foo.txt", false); // `false` makes the request synchronous
request.send(null);
if (request.status === 200) {
console.log(request.responseText);
}
Der request.send
-Aufruf sendet die Anfrage. Der null
-Parameter zeigt an, dass für die GET
-Anfrage kein Inhaltskörper benötigt wird.
Die if
-Anweisung überprüft den Statuscode, nachdem die Transaktion abgeschlossen ist. Wenn das Ergebnis 200 — das "OK"-Ergebnis von HTTP — beträgt, wird der Textinhalt des Dokuments an die Konsole ausgegeben.
Beispiel: Synchrone HTTP-Anfrage von einem Worker
Einer der wenigen Fälle, in denen eine synchrone Anfrage normalerweise die Ausführung nicht blockiert, ist die Verwendung von XMLHttpRequest
innerhalb eines Worker
.
example.html
(die Hauptseite):
<!doctype html>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>MDN Example</title>
<script>
const worker = new Worker("myTask.js");
worker.onmessage = (event) => {
alert(`Worker said: ${event.data}`);
};
worker.postMessage("Hello");
</script>
</head>
<body>
…
</body>
</html>
myFile.txt
(das Ziel der synchronen XMLHttpRequest
-Aufruf):
Hello World!!
myTask.js
(der Worker
):
self.onmessage = (event) => {
if (event.data === "Hello") {
const xhr = new XMLHttpRequest();
xhr.open("GET", "myFile.txt", false); // synchronous request
xhr.send(null);
self.postMessage(xhr.responseText);
}
};
Hinweis:
Der Effekt ist asynchron aufgrund der Verwendung des Worker
.
Dieses Muster kann nützlich sein, beispielsweise um im Hintergrund mit dem Server zu interagieren oder um Inhalte vorab zu laden. Siehe Verwendung von Web-Workern für Beispiele und Details.
Anpassung von Sync XHR-Anwendungsfällen an die Beacon API
Es gibt einige Fälle, in denen die synchrone Verwendung von XMLHttpRequest
nicht ersetzbar ist, wie während der unload
, beforeunload
und pagehide
Ereignisse. Sie sollten in Betracht ziehen, die fetch()
-API mit dem keepalive
-Flag zu verwenden. Wenn fetch
mit keepalive
nicht verfügbar ist, können Sie die navigator.sendBeacon()
API in Betracht ziehen, die diese Anwendungsfälle unterstützen kann und dabei typischerweise eine gute Benutzererfahrung liefert.
Das folgende Beispiel zeigt theoretischen Analytik-Code, der versucht, Daten an einen Server zu senden, indem er ein XMLHttpRequest
im Unload-Handler synchron verwendet. Dies führt dazu, dass das Entladen der Seite verzögert wird.
window.addEventListener("unload", logData, false);
function logData() {
const client = new XMLHttpRequest();
client.open("POST", "/log", false); // third parameter indicates sync xhr. :(
client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
client.send(analyticsData);
}
Mit der sendBeacon()
-Methode werden die Daten asynchron an den Webserver übertragen, wenn der User Agent Gelegenheit dazu hatte, ohne das Entladen zu verzögern oder die Leistung der nächsten Navigation zu beeinträchtigen.
Das folgende Beispiel zeigt ein theoretisches Analytik-Code-Muster, das Daten an einen Server über die sendBeacon()
-Methode übermittelt.
window.addEventListener("unload", logData, false);
function logData() {
navigator.sendBeacon("/log", analyticsData);
}