Start · Sprachen · JavaScript · Referenz · ProgressEvent.lengthComputable

ProgressEvent.lengthComputable

Eigenschaft

Schreibgeschütztes boolesches Flag, das angibt, ob die Gesamtgröße (<code>total</code>) der übertragenen Ressource bekannt ist und sich ein Fortschritt berechnen lässt.

seit JavaScript Baseline: alle Browser Kategorie: webapi

Signatur

ProgressEvent.lengthComputable

Beschreibung

lengthComputable ist eine schreibgeschützte Eigenschaft von ProgressEvent. Sie ist true, wenn der Browser die Gesamtgröße der Übertragung kennt. Dann enthält ProgressEvent.total einen sinnvollen Wert, und loaded / total liefert einen echten Prozentwert. Ist sie false, steht total auf 0. In diesem Fall ist nur die bisher übertragene Menge (loaded) bekannt.

In der Praxis kommt die Eigenschaft vor allem bei XMLHttpRequest vor, sowohl beim Herunterladen (xhr.onprogress) als auch beim Hochladen (xhr.upload.onprogress). Außerdem liefern FileReader und die Ereignisse loadstart, progress, load und loadend solche Events. Beim Download hängt der Wert meist davon ab, ob der Server einen gültigen Content-Length-Header schickt.

Prüfe lengthComputable immer, bevor du einen Prozentwert berechnest. Sonst teilst du durch 0 und bekommst NaN oder Infinity. Ist die Länge unbekannt, zeigst du am besten eine unbestimmte Fortschrittsanzeige an, zum Beispiel ein <progress>-Element ohne value, oder nur die geladenen Bytes.

Rückgabewert

Typ
boolean
Beschreibung
true, wenn die Gesamtgröße bekannt ist und total einen gültigen Wert hat, sonst false.

Beispiele

Download-Fortschritt mit XMLHttpRequest

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

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

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

Upload-Fortschritt in einem <progress>-Element

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

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

  const xhr = new XMLHttpRequest();
  xhr.upload.onprogress = (event) => {
    if (event.lengthComputable) {
      bar.max = event.total;
      bar.value = event.loaded;
    } else {
      // unbestimmte Anzeige: value entfernen
      bar.removeAttribute('value');
    }
  };
  xhr.open('POST', '/upload');
  xhr.send(formData);
});

Datei lokal einlesen mit FileReader

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

input.addEventListener('change', () => {
  const reader = new FileReader();
  reader.onprogress = (event) => {
    console.log('lengthComputable:', event.lengthComputable);
    if (event.lengthComputable) {
      console.log(`${(event.loaded / event.total * 100).toFixed(1)} % gelesen`);
    }
  };
  reader.onload = () => console.log('Datei gelesen');
  reader.readAsArrayBuffer(input.files[0]);
});
lengthComputable: true 100.0 % gelesen Datei gelesen

Eigenes ProgressEvent erzeugen

const e1 = new ProgressEvent('progress', { lengthComputable: true, loaded: 50, total: 200 });
const e2 = new ProgressEvent('progress', { loaded: 50 });

console.log(e1.lengthComputable, e1.loaded / e1.total);
console.log(e2.lengthComputable, e2.total);
true 0.25 false 0

// Wichtig · Fallstricke

  • Nicht auf total verlassen: Wenn lengthComputable false ist, steht total auf 0. Die Rechnung loaded / total ergibt dann Infinity (wenn loaded > 0) oder NaN (wenn loaded ebenfalls 0 ist).
  • Komprimierte Antworten: Wenn der Server mit Content-Encoding: gzip oder br antwortet oder Transfer-Encoding: chunked nutzt, ist die Länge oft unbekannt. Bei komprimierten Antworten kann loaded (entpackte Bytes) je nach Browser auch größer als total (komprimierte Bytes laut Content-Length) werden.
  • CORS: Bei Anfragen an eine andere Herkunft ist der Content-Length-Header lesbar, weil er zu den CORS-sicheren Antwort-Headern gehört. Für Upload-Progress-Events löst ein Listener auf xhr.upload jedoch eine Preflight-Anfrage aus.
  • Fetch API: fetch() erzeugt keine ProgressEvents. Den Fortschritt musst du dort selbst über response.body.getReader() und den Content-Length-Header berechnen.
  • Die Eigenschaft ist schreibgeschützt. Bei eigenen Events setzt du sie über das Init-Objekt des Konstruktors. Die Unterstützung ist in allen modernen Browsern vorhanden, ebenso in Web Workern.