Signatur
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
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();
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]);
});
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);
// Wichtig · Fallstricke
- Nicht auf
totalverlassen: WennlengthComputablefalseist, stehttotalauf0. Die Rechnungloaded / totalergibt dannInfinity(wennloaded > 0) oderNaN(wennloadedebenfalls0ist). - Komprimierte Antworten: Wenn der Server mit
Content-Encoding: gzipoderbrantwortet oderTransfer-Encoding: chunkednutzt, ist die Länge oft unbekannt. Bei komprimierten Antworten kannloaded(entpackte Bytes) je nach Browser auch größer alstotal(komprimierte Bytes lautContent-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 aufxhr.uploadjedoch eine Preflight-Anfrage aus. - Fetch API:
fetch()erzeugt keineProgressEvents. Den Fortschritt musst du dort selbst überresponse.body.getReader()und denContent-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.