Start · Sprachen · JavaScript · Referenz · FileReader.abort()

FileReader.abort()

Methode

Bricht einen laufenden Lesevorgang eines <code>FileReader</code> ab. Danach ist <code>readyState</code> gleich <code>DONE</code>, <code>result</code> ist <code>null</code> und die Ereignisse <code>abort</code> und <code>loadend</code> werden ausgelöst.

seit JavaScript Baseline: alle Browser (File API) Kategorie: webapi

Signatur

FileReader.prototype.abort()

Beschreibung

abort() beendet einen Lesevorgang, der mit readAsArrayBuffer(), readAsText(), readAsDataURL() oder readAsBinaryString() gestartet wurde. Das ist vor allem bei großen Dateien nützlich: Wählt der Nutzer eine andere Datei, klickt auf „Abbrechen“ oder dauert das Lesen zu lange, gibt man damit Ressourcen frei, statt auf das Ende zu warten.

Läuft gerade ein Lesevorgang (readyState === FileReader.LOADING), passiert beim Aufruf Folgendes:

  • readyState wird auf FileReader.DONE (2) gesetzt.
  • result wird auf null gesetzt. Schon gelesene Teildaten gehen verloren.
  • Noch ausstehende progress- und load-Ereignisse werden verworfen.
  • Zuerst wird das Ereignis abort ausgelöst, danach loadend. load und error kommen nicht.

Ist der Reader noch leer (EMPTY) oder schon fertig (DONE), setzt der Aufruf nur result auf null. Ereignisse werden dann nicht ausgelöst. Ein Fehler tritt dabei nicht auf, du kannst abort() also ohne Prüfung aufrufen.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Ob der Abbruch geklappt hat, erkennst du am Ereignis abort bzw. an readyState und result.

Beispiele

Abbrechen-Button beim Einlesen einer großen Datei

// HTML: <input type="file" id="datei"> <button id="abbrechen">Abbrechen</button> <progress id="fortschritt" max="100" value="0"></progress>
const input = document.querySelector('#datei');
const abbrechenBtn = document.querySelector('#abbrechen');
const fortschritt = document.querySelector('#fortschritt');

const reader = new FileReader();

reader.addEventListener('progress', (e) => {
  if (e.lengthComputable) {
    fortschritt.value = Math.round((e.loaded / e.total) * 100);
  }
});

reader.addEventListener('load', () => {
  console.log(`Fertig: ${reader.result.byteLength} Bytes gelesen`);
});

reader.addEventListener('abort', () => {
  console.log('Lesevorgang abgebrochen, result =', reader.result);
  fortschritt.value = 0;
});

reader.addEventListener('loadend', () => {
  console.log('loadend, readyState =', reader.readyState);
});

input.addEventListener('change', () => {
  const [file] = input.files;
  if (!file) return;
  // Läuft noch ein Lesevorgang? Erst abbrechen, sonst gibt es einen InvalidStateError
  if (reader.readyState === FileReader.LOADING) reader.abort();
  reader.readAsArrayBuffer(file);
});

abbrechenBtn.addEventListener('click', () => reader.abort());
Lesevorgang abgebrochen, result = null loadend, readyState = 2

Lesevorgang nach einem Timeout abbrechen

const leseMitTimeout = (file, ms = 3000) =>
  new Promise((resolve, reject) => {
    const reader = new FileReader();
    const timer = setTimeout(() => reader.abort(), ms);

    reader.onload = () => resolve(reader.result);
    reader.onerror = () => reject(reader.error);
    reader.onabort = () => reject(new DOMException(`Timeout nach ${ms} ms`, 'TimeoutError'));
    reader.onloadend = () => clearTimeout(timer);

    reader.readAsText(file);
  });

// Verwendung
const file = new File(['Hallo Welt'], 'gruss.txt', { type: 'text/plain' });
try {
  const text = await leseMitTimeout(file, 5000);
  console.log(text);
} catch (err) {
  console.warn(err.name, err.message);
}
Hallo Welt

FileReader mit AbortSignal steuern

const leseAlsDataURL = (blob, { signal } = {}) =>
  new Promise((resolve, reject) => {
    if (signal?.aborted) {
      reject(signal.reason);
      return;
    }
    const reader = new FileReader();
    const onAbortSignal = () => reader.abort();
    signal?.addEventListener('abort', onAbortSignal, { once: true });

    reader.onload = () => resolve(reader.result);
    reader.onerror = () => reject(reader.error);
    reader.onabort = () => reject(signal?.reason ?? new DOMException('Abgebrochen', 'AbortError'));
    reader.onloadend = () => signal?.removeEventListener('abort', onAbortSignal);

    reader.readAsDataURL(blob);
  });

const controller = new AbortController();
const blob = new Blob([new Uint8Array(50_000_000)]);
const promise = leseAlsDataURL(blob, { signal: controller.signal });
controller.abort(); // sofort abbrechen

try {
  await promise;
} catch (err) {
  console.log('Abgebrochen:', err.name);
}
Abgebrochen: AbortError

// Wichtig · Fallstricke

  • Kein load nach dem Abbruch: Wer nur auf load hört, bekommt einen Abbruch nicht mit. Aufräumarbeiten wie Timer löschen oder die Oberfläche zurücksetzen gehören deshalb in loadend, denn das kommt immer, egal ob der Vorgang geklappt hat, fehlgeschlagen ist oder abgebrochen wurde.
  • Teildaten gehen verloren: Nach abort() ist result immer null. Willst du einen Teil der Datei lesen, schneide die Datei vorher mit Blob.prototype.slice() zu.
  • Neuer Lesevorgang: Startest du einen readAs…()-Aufruf, während der Reader noch im Zustand LOADING ist, gibt es einen InvalidStateError. Rufe vorher abort() auf oder nimm einfach eine neue FileReader-Instanz.
  • error-Eigenschaft: Laut älteren Fassungen der Spezifikation wurde reader.error nach dem Abbruch auf einen AbortError gesetzt, laut der aktuellen nicht mehr. Verlass dich deshalb nicht darauf, sondern werte das Ereignis abort aus.
  • Moderne Alternative: Blob.prototype.text(), arrayBuffer() und stream() geben Promises bzw. Streams zurück. Streams brichst du mit ReadableStreamDefaultReader.cancel() ab. Die Promise-Varianten kann man nicht abbrechen, für abbrechbares Lesen ist FileReader daher weiterhin sinnvoll.
  • Kompatibilität: Wird von allen aktuellen Browsern unterstützt, auch in Web Workern. Node.js hat keinen FileReader.