Start · Sprachen · JavaScript · Referenz · XMLHttpRequestEventTarget: progress

XMLHttpRequestEventTarget: progress

Ereignis

Wird während einer laufenden <code>XMLHttpRequest</code>-Übertragung wiederholt ausgelöst, sobald neue Daten empfangen (oder beim Upload gesendet) wurden.

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

Signatur

xhr.addEventListener("progress", handler) / xhr.upload.addEventListener("progress", handler)

Beschreibung

Das progress-Ereignis gehört zum Interface XMLHttpRequestEventTarget, das sowohl von XMLHttpRequest selbst als auch von XMLHttpRequestUpload (erreichbar über xhr.upload) implementiert wird. Es wird periodisch ausgelöst – laut Spezifikation etwa alle 50 ms –, solange Daten übertragen werden. Auf xhr meldet es den Download-Fortschritt der Antwort, auf xhr.upload den Upload-Fortschritt des Request-Bodys.

Der Handler erhält ein ProgressEvent mit den Eigenschaften loaded (bisher übertragene Bytes), total (Gesamtgröße in Bytes) und lengthComputable (ob total bekannt ist). Damit lassen sich Fortschrittsbalken, Prozentanzeigen oder Restzeit-Schätzungen umsetzen – ein klassischer Anwendungsfall sind Datei-Uploads und große Downloads.

Registrieren lässt sich der Handler entweder per addEventListener("progress", handler) oder über die Eigenschaft onprogress. Die Listener müssen vor dem Aufruf von send() gesetzt werden – beim Upload sogar zwingend, da sonst in manchen Browsern gar keine Upload-Ereignisse erzeugt werden. Die Ereignisfolge lautet typischerweise loadstart → mehrere progress → load/error/abort/timeout → loadend.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "progress".
$handler Pflicht (event: ProgressEvent) => void Callback, der bei jedem Fortschrittsschritt ein ProgressEvent mit loaded, total und lengthComputable erhält.
$options boolean|AddEventListenerOptions false Optionale Listener-Optionen wie once oder signal (zum Entfernen per AbortController).

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Der Handler bekommt ein ProgressEvent-Objekt übergeben.

Beispiele

Download-Fortschritt in Prozent anzeigen

const xhr = new XMLHttpRequest();
xhr.open('GET', '/dateien/grosses-video.mp4');
xhr.responseType = 'blob';

xhr.addEventListener('progress', (event) => {
  if (event.lengthComputable) {
    const prozent = Math.round((event.loaded / event.total) * 100);
    console.log(`Download: ${prozent} %`);
  } else {
    console.log(`Empfangen: ${event.loaded} Bytes (Gesamtgröße unbekannt)`);
  }
});

xhr.addEventListener('load', () => console.log('Fertig, Status', xhr.status));
xhr.send();
Download: 12 % Download: 47 % Download: 100 % Fertig, Status 200

Upload-Fortschritt mit <progress>-Element (onprogress)

const input = document.querySelector('#datei');
const balken = document.querySelector('progress');

input.addEventListener('change', () => {
  const formData = new FormData();
  formData.append('datei', input.files[0]);

  const xhr = new XMLHttpRequest();
  // Upload-Listener MUSS vor send() registriert werden
  xhr.upload.onprogress = (event) => {
    if (event.lengthComputable) {
      balken.max = event.total;
      balken.value = event.loaded;
    }
  };
  xhr.upload.onload = () => console.log('Upload abgeschlossen');

  xhr.open('POST', '/api/upload');
  xhr.send(formData);
});
Upload abgeschlossen

Listener wieder entfernen und Übertragungsrate messen

const xhr = new XMLHttpRequest();
const start = performance.now();

const onProgress = (event) => {
  const sekunden = (performance.now() - start) / 1000;
  const kbps = (event.loaded / 1024 / sekunden).toFixed(1);
  console.log(`${kbps} KiB/s`);
};

xhr.addEventListener('progress', onProgress);
xhr.addEventListener('loadend', () => {
  // Aufräumen, sobald die Anfrage beendet ist
  xhr.removeEventListener('progress', onProgress);
  console.log('Listener entfernt');
});

xhr.open('GET', '/daten/export.csv');
xhr.send();
812.4 KiB/s 1040.7 KiB/s Listener entfernt

// Wichtig · Fallstricke

  • lengthComputable prüfen: Fehlt der Content-Length-Header (z. B. bei Transfer-Encoding: chunked), ist total gleich 0. Bei komprimierten Antworten (gzip/br) beziehen sich loaded und total je nach Browser auf die komprimierten Bytes – Prozentwerte können dann ungenau sein.
  • Upload-Listener vor send(): Wird xhr.upload.onprogress erst nach send() gesetzt, werden keine Upload-Ereignisse gemeldet. Außerdem löst ein Upload-Listener bei Cross-Origin-Anfragen einen CORS-Preflight (OPTIONS) aus.
  • Kein garantiertes 100-%-Ereignis: Kleine Antworten können ganz ohne progress auskommen. Den Abschluss immer über load bzw. loadend behandeln, nicht über loaded === total.
  • Performance: Das Ereignis kann sehr häufig feuern; aufwendige DOM-Updates ggf. per requestAnimationFrame drosseln.
  • Kompatibilität: In allen modernen Browsern unterstützt. Die fetch()-API bietet kein vergleichbares Ereignis – Download-Fortschritt dort nur über response.body.getReader(), Upload-Fortschritt praktisch nur mit XHR.