Start · Sprachen · JavaScript · Referenz · XMLHttpRequestEventTarget: timeout

XMLHttpRequestEventTarget: timeout

Ereignis

Wird ausgelöst, wenn eine <code>XMLHttpRequest</code>-Anfrage abgebrochen wird, weil die in <code>xhr.timeout</code> festgelegte Zeit abgelaufen ist.

seit JavaScript Baseline: alle Browser (XMLHttpRequest Level 2) Kategorie: webapi

Signatur

xhr.addEventListener("timeout", handler) / xhr.ontimeout = handler

Beschreibung

Das timeout-Ereignis gehört zu XMLHttpRequestEventTarget und tritt auf, wenn eine Anfrage länger dauert als die in der Eigenschaft XMLHttpRequest.timeout (in Millisekunden) festgelegte Zeit. Der Browser bricht die Anfrage dann selbst ab. Der Handler erhält ein ProgressEvent.

Das Ereignis lässt sich auf zwei Wegen abonnieren: mit xhr.addEventListener("timeout", handler) oder über die Eigenschaft xhr.ontimeout = handler. Es gibt dasselbe Ereignis auch auf xhr.upload (einem XMLHttpRequestUpload-Objekt). Dort feuert es, wenn der Upload noch läuft, während die Zeit abläuft.

Die Reihenfolge der Ereignisse bei einer Zeitüberschreitung ist: readystatechange (mit readyState 4), dann timeout, dann loadend. Nicht ausgelöst werden load und error. Wenn du Zeitüberschreitungen gezielt behandeln willst, etwa um es erneut zu versuchen oder eine Meldung anzuzeigen, brauchst du also einen eigenen timeout-Handler.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Name des Ereignisses: "timeout" (nur bei addEventListener).
$handler Pflicht (event: ProgressEvent) => void Callback, der bei einer Zeitüberschreitung aufgerufen wird. Er erhält ein ProgressEvent mit loaded, total und lengthComputable.
$options boolean | AddEventListenerOptions false Optionen wie { once: true } oder signal zum späteren Entfernen.

Rückgabewert

Typ
void
Beschreibung
Der Handler gibt nichts zurück. addEventListener gibt undefined zurück.

Beispiele

Zeitüberschreitung mit addEventListener behandeln

const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/langsame-antwort');
xhr.timeout = 3000; // 3 Sekunden

xhr.addEventListener('load', () => {
  console.log('Antwort:', xhr.status);
});

xhr.addEventListener('timeout', (event) => {
  console.warn(`Zeitüberschreitung nach ${xhr.timeout} ms – ${event.loaded} Bytes empfangen`);
});

xhr.send();
Zeitüberschreitung nach 3000 ms – 0 Bytes empfangen

ontimeout-Eigenschaft und Handler wieder entfernen

const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/status');
xhr.timeout = 2000;

const onTimeout = () => console.warn('Server antwortet nicht.');

// Variante 1: on-Property
xhr.ontimeout = onTimeout;

// Variante 2: Listener hinzufügen und später entfernen
xhr.addEventListener('timeout', onTimeout);
xhr.removeEventListener('timeout', onTimeout);

// on-Property wieder löschen
// xhr.ontimeout = null;

xhr.send();
Server antwortet nicht.

Promise-Wrapper mit automatischem Neuversuch

const request = (url, { timeout = 2000, retries = 2 } = {}) =>
  new Promise((resolve, reject) => {
    const attempt = (left) => {
      const xhr = new XMLHttpRequest();
      xhr.open('GET', url);
      xhr.timeout = timeout;
      xhr.onload = () => resolve(xhr.responseText);
      xhr.onerror = () => reject(new Error('Netzwerkfehler'));
      xhr.ontimeout = () => {
        if (left > 0) {
          console.log(`Timeout – noch ${left} Versuch(e)`);
          attempt(left - 1);
        } else {
          reject(new Error(`Timeout nach ${timeout} ms`));
        }
      };
      xhr.send();
    };
    attempt(retries);
  });

try {
  const text = await request('/api/daten');
  console.log(text);
} catch (err) {
  console.error(err.message);
}
Timeout – noch 2 Versuch(e) Timeout – noch 1 Versuch(e) Timeout nach 2000 ms

// Wichtig · Fallstricke

  • Ohne xhr.timeout kein Ereignis: Der Standardwert ist 0, also kein Zeitlimit. In diesem Fall feuert timeout nie.
  • Synchrone Anfragen: Setzt du timeout bei einer synchronen Anfrage (open(..., false)) in einem Dokument-Kontext, wirft der Browser eine InvalidAccessError-DOMException. In Workern ist das erlaubt.
  • Bei einer Zeitüberschreitung feuern weder load noch error, wohl aber loadend. Wer Aufräumarbeiten nur im error-Handler erledigt, verpasst diesen Fall.
  • Das Zeitlimit gilt für die gesamte Anfrage, gezählt ab send(). Du kannst xhr.timeout auch noch ändern, während die Anfrage läuft. Maßgeblich bleibt der Startzeitpunkt.
  • xhr.upload.ontimeout feuert zusätzlich, wenn der Upload bei Ablauf der Zeit noch nicht abgeschlossen war.
  • Kompatibilität: Alle modernen Browser unterstützen das Ereignis. Im Internet Explorer ab Version 8 gab es timeout nur eingeschränkt. Für neuen Code empfiehlt sich fetch() mit AbortSignal.timeout().