Signatur
Beschreibung
Das Ereignis readystatechange wird bei jedem Wechsel von XMLHttpRequest.readyState ausgelöst. Den Handler registriert man entweder mit xhr.addEventListener("readystatechange", handler) oder über die Eigenschaft xhr.onreadystatechange = handler. Das Ereignis ist ein einfaches Event ohne zusätzliche Eigenschaften, es lässt sich nicht abbrechen (nicht cancelable) und steigt nicht auf (bubbles: false).
Der Wert von readyState durchläuft diese Zustände:
0–UNSENT: Objekt erzeugt,open()noch nicht aufgerufen1–OPENED:open()wurde aufgerufen2–HEADERS_RECEIVED: Antwort-Header und Status sind da3–LOADING: der Antwortkörper wird geladen,responseTextenthält bereits Teildaten4–DONE: die Anfrage ist abgeschlossen – erfolgreich oder mit Fehler
Historisch war onreadystatechange der Weg, um auf AJAX-Antworten zu reagieren. Heute sind die spezielleren Ereignisse load, error, progress und loadend meist übersichtlicher, und in neuem Code verwendet man in der Regel gleich fetch(). Nützlich bleibt readystatechange vor allem, um schon bei HEADERS_RECEIVED Header auszuwerten oder um älteren Code zu pflegen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "readystatechange". |
|
| $handler Pflicht | (event: Event) => void | Callback, der ein einfaches Event erhält. event.target bzw. this (bei normalen Funktionen) ist das XMLHttpRequest-Objekt. |
|
| $options | boolean | AddEventListenerOptions | false | Optionen wie { once: true } oder { signal } für addEventListener. |
Rückgabewert
addEventListener gibt nichts zurück. Den aktuellen Zustand liest man im Handler aus xhr.readyState.Beispiele
Klassisch: JSON laden mit onreadystatechange
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/users/1");
xhr.responseType = "json";
xhr.onreadystatechange = () => {
// Erst im Zustand DONE (4) ist die Antwort vollständig
if (xhr.readyState !== XMLHttpRequest.DONE) return;
if (xhr.status >= 200 && xhr.status < 300) {
console.log("Benutzer:", xhr.response.name);
} else {
console.error("Fehler:", xhr.status || "Netzwerkfehler");
}
};
xhr.send();
Alle Zustandswechsel mit addEventListener protokollieren
const states = ["UNSENT", "OPENED", "HEADERS_RECEIVED", "LOADING", "DONE"];
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", () => {
console.log(`${xhr.readyState} ${states[xhr.readyState]}`);
});
xhr.open("GET", "/daten.txt");
xhr.send();
Frühzeitig abbrechen, wenn die Header nicht passen
const xhr = new XMLHttpRequest();
const onStateChange = () => {
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
const size = Number(xhr.getResponseHeader("Content-Length"));
if (size > 5_000_000) {
console.warn(`Datei zu groß (${size} Bytes) – Abbruch`);
xhr.abort();
}
}
if (xhr.readyState === XMLHttpRequest.DONE) {
// Listener entfernen, sobald er nicht mehr gebraucht wird
xhr.removeEventListener("readystatechange", onStateChange);
}
};
xhr.addEventListener("readystatechange", onStateChange);
xhr.open("GET", "/downloads/video.mp4");
xhr.send();
In ein Promise verpacken
const request = (method, url) =>
new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) return;
xhr.status >= 200 && xhr.status < 300
? resolve(xhr.responseText)
: reject(new Error(`HTTP ${xhr.status}`));
};
xhr.send();
});
const text = await request("GET", "/hallo.txt");
console.log(text);
// Wichtig · Fallstricke
- Status 0 bei DONE: Bei Netzwerkfehlern, CORS-Blockaden oder
abort()wird ebenfallsreadyState === 4erreicht, aber mitstatus === 0. Prüfe deshalb immer auchstatus– oder nutze zusätzlich die Ereignisseerrorundabort. - LOADING kann mehrfach feuern: Zustand
3kann je nach Browser bei jedem empfangenen Datenblock erneut gemeldet werden. Für Fortschrittsanzeigen istprogressbesser geeignet. - Synchrone Anfragen: Bei
open(method, url, false)werden nicht alle Zwischenzustände zuverlässig gemeldet. Synchrone XHR im Hauptthread sind außerdem veraltet und blockieren die Oberfläche. - Reihenfolge:
onreadystatechangesollte vorsend()(am besten voropen()) gesetzt werden, sonst gehen frühe Zustandswechsel verloren. Eine erneute Zuweisung der on-Eigenschaft überschreibt den vorherigen Handler,addEventListenerdagegen erlaubt mehrere Handler. - Kompatibilität: Wird von allen Browsern unterstützt, auch in Web Workern. Service Worker haben kein
XMLHttpRequest– dort nurfetch(). In Node.js gibt es XHR nicht nativ.