Start · Sprachen · JavaScript · Referenz · ProgressEvent

ProgressEvent

Schnittstelle

Ereignis-Schnittstelle, die den Fortschritt eines laufenden Vorgangs meldet, z. B. Up- oder Download per <code>XMLHttpRequest</code> oder Lesen einer Datei mit <code>FileReader</code>.

seit JavaScript Baseline: alle Browser Kategorie: webapi

Signatur

interface ProgressEvent extends Event

Beschreibung

ProgressEvent erbt von Event und beschreibt, wie weit ein länger laufender Vorgang schon ist. Ausgelöst wird es unter anderem von XMLHttpRequest, XMLHttpRequestUpload (über xhr.upload) und FileReader. Die Ereignistypen sind loadstart, progress, load, error, abort, timeout und loadend.

Zusätzlich zu den Eigenschaften von Event gibt es drei schreibgeschützte Eigenschaften:

  • lengthComputable (boolean): true, wenn die Gesamtgröße bekannt ist, z. B. über den Header Content-Length.
  • loaded (number): Bytes, die bereits übertragen oder verarbeitet wurden.
  • total (number): Gesamtgröße in Bytes. Ist sie unbekannt, ist der Wert 0.

Typischer Einsatz sind Fortschrittsbalken für Datei-Uploads, große Downloads oder das Einlesen lokaler Dateien. Mit dem Konstruktor new ProgressEvent(type, init) kann man solche Ereignisse auch selbst erzeugen, etwa für Tests oder eigene Lade-Komponenten.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Name des Ereignisses (Konstruktor-Parameter), z. B. "progress" oder "load".
$options ProgressEventInit {} Objekt mit lengthComputable (Standard false), loaded (Standard 0) und total (Standard 0) sowie den EventInit-Feldern bubbles, cancelable und composed.

Rückgabewert

Typ
ProgressEvent
Beschreibung
Ein neues ProgressEvent-Objekt (beim Konstruktor-Aufruf).

Beispiele

Upload-Fortschritt mit XMLHttpRequest anzeigen

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();
  xhr.open('POST', '/api/upload');

  // Upload-Fortschritt: Die Listener hängen an xhr.upload, nicht an xhr
  xhr.upload.addEventListener('progress', (event) => {
    if (event.lengthComputable) {
      const prozent = Math.round((event.loaded / event.total) * 100);
      balken.value = prozent;
      console.log(`Upload: ${prozent} %`);
    }
  });

  xhr.addEventListener('loadend', (event) => {
    console.log(`Fertig, Status ${xhr.status}, ${event.loaded} Bytes`);
  });

  xhr.send(formData);
});
Upload: 12 % Upload: 57 % Upload: 100 % Fertig, Status 200, 523 Bytes

Lokale Datei mit FileReader einlesen

const input = document.querySelector('input[type=file]');

input.addEventListener('change', () => {
  const reader = new FileReader();

  reader.onprogress = (event) => {
    if (event.lengthComputable) {
      console.log(`Gelesen: ${event.loaded} von ${event.total} Bytes`);
    }
  };

  reader.onload = (event) => {
    console.log(event instanceof ProgressEvent); // true
    console.log('Zeichen:', reader.result.length);
  };

  reader.onerror = () => console.error('Fehler:', reader.error);

  reader.readAsText(input.files[0]);
});
Gelesen: 1048576 von 2097152 Bytes Gelesen: 2097152 von 2097152 Bytes true Zeichen: 2097152

Eigenes ProgressEvent erzeugen und auslösen

const lader = new EventTarget();

lader.addEventListener('progress', (e) => {
  const anteil = e.lengthComputable ? (e.loaded / e.total) * 100 : NaN;
  console.log(e.type, e.loaded, e.total, `${anteil} %`);
});

const ereignis = new ProgressEvent('progress', {
  lengthComputable: true,
  loaded: 30,
  total: 120
});

lader.dispatchEvent(ereignis);
progress 30 120 25 %

// Wichtig · Fallstricke

  • Nicht immer bekannte Gesamtgröße: Prüfe vor jeder Division lengthComputable. Ist es false, ist total gleich 0 und loaded / total ergibt Infinity. Das passiert, wenn der Server kein Content-Length mitschickt, etwa bei Chunked Encoding.
  • Komprimierung: Bei gzip/br-Antworten kann sich loaded auf die komprimierten Bytes beziehen, der Wert ist dann je nach Browser nicht genau vergleichbar.
  • Upload-Listener rechtzeitig setzen: Listener auf xhr.upload müssen vor send() registriert werden. Außerdem lösen sie bei Cross-Origin-Anfragen einen CORS-Preflight aus.
  • fetch() hat keine Fortschritts-Ereignisse: Für den Download-Fortschritt liest man response.body (ein ReadableStream) und zählt die Bytes selbst. Für den Upload-Fortschritt ist XMLHttpRequest weiterhin die verlässliche Lösung.
  • Häufigkeit: progress wird etwa alle 50 ms oder seltener ausgelöst. Rechenintensive Aktualisierungen der Oberfläche sollte man drosseln, z. B. mit requestAnimationFrame.
  • In Workern gibt es die Schnittstelle ebenfalls. Der Konstruktor wird von allen modernen Browsern unterstützt.