Start · Sprachen · JavaScript · Referenz · TextDecoderStream

TextDecoderStream

Schnittstelle

Ein <code>TransformStream</code>, der einen Strom von Binärdaten (z. B. UTF-8-Bytes) fortlaufend in einen Strom von Zeichenketten umwandelt.

seit JavaScript Baseline 2023: alle modernen Browser (Chrome 71+, Kategorie: webapi

Signatur

interface TextDecoderStream

Beschreibung

TextDecoderStream ist die Stream-Variante von TextDecoder aus der Encoding API. Das Objekt hat eine writable-Seite, die Byte-Blöcke (Uint8Array, ArrayBuffer oder DataView) annimmt, und eine readable-Seite, die dekodierte Zeichenketten liefert. Damit passt es direkt in ReadableStream.prototype.pipeThrough().

Am nützlichsten ist es beim Verarbeiten großer oder laufend eintreffender Textdaten, etwa bei einem fetch()-Antwortkörper, Server-Sent-Daten, NDJSON-Logs oder der Ausgabe von KI-Modellen, die Token für Token gestreamt wird. Du musst nicht auf die komplette Antwort warten (response.text()) und kannst jeden Block sofort weiterverarbeiten.

Der Stream kümmert sich selbst um Mehrbyte-Zeichen, die über Blockgrenzen hinweg zerteilt sind: Unvollständige Bytefolgen werden zurückgehalten, bis der nächste Block kommt. Bei einem Aufruf von TextDecoder.decode() pro Block würden solche Zeichen dagegen beschädigt, außer du übergibst { stream: true }.

Eigenschaften (alle schreibgeschützt): encoding (Name der Kodierung, z. B. "utf-8"), fatal, ignoreBOM, readable (ReadableStream<string>) und writable (WritableStream<BufferSource>).

Parameter

Name Typ Default Beschreibung
$label string "utf-8" Bezeichnung der Kodierung, z. B. "utf-8", "iso-8859-1", "windows-1252", "utf-16le". Bei einer unbekannten Bezeichnung wird ein RangeError geworfen.
$options object {} Optionales Einstellungsobjekt.
$options.fatal boolean false Bei true bricht ungültige Byte-Eingabe den Stream mit einem TypeError ab. Bei false wird sie durch U+FFFD (�) ersetzt.
$options.ignoreBOM boolean false Bei true bleibt eine Byte Order Mark (BOM) im Ausgabetext erhalten. Standardmäßig wird sie entfernt.

Rückgabewert

Typ
TextDecoderStream
Beschreibung
Eine neue Instanz mit den Eigenschaften readable und writable, die sich mit pipeThrough() einsetzen lässt.

Beispiele

fetch-Antwort Stück für Stück als Text lesen

const response = await fetch('/api/grosse-datei.txt');

// Bytes → Zeichenketten
const textStream = response.body.pipeThrough(new TextDecoderStream());

let zeichen = 0;
for await (const chunk of textStream) {
  zeichen += chunk.length;
  console.log('Block empfangen:', chunk.slice(0, 40));
}
console.log(`Fertig, ${zeichen} Zeichen gelesen.`);
Block empfangen: Lorem ipsum dolor sit amet, consectetur ... Fertig, 184233 Zeichen gelesen.

Instanz erzeugen und Eigenschaften prüfen

const decoder = new TextDecoderStream('windows-1252', { fatal: false });

console.log(decoder.encoding);   // Name der Kodierung
console.log(decoder.fatal);
console.log(decoder.ignoreBOM);
console.log(decoder.readable instanceof ReadableStream);
console.log(decoder.writable instanceof WritableStream);
windows-1252 false false true true

Zerteiltes Mehrbyte-Zeichen korrekt dekodieren

// „€“ ist in UTF-8 die Folge 0xE2 0x82 0xAC. Hier wird sie über zwei Blöcke verteilt.
const quelle = new ReadableStream({
  start(controller) {
    controller.enqueue(new Uint8Array([0x50, 0x72, 0x65, 0x69, 0x73, 0x3A, 0x20, 0xE2]));
    controller.enqueue(new Uint8Array([0x82, 0xAC, 0x20, 0x35]));
    controller.close();
  }
});

const teile = [];
for await (const text of quelle.pipeThrough(new TextDecoderStream())) {
  teile.push(text);
}
console.log(teile);
console.log(teile.join(''));
[ 'Preis: ', '€ 5' ] Preis: € 5

NDJSON-Stream zeilenweise parsen

// Hilfs-TransformStream: teilt Text an Zeilenumbrüchen auf
const zeilenSplitter = () => {
  let rest = '';
  return new TransformStream({
    transform(chunk, controller) {
      const zeilen = (rest + chunk).split('\n');
      rest = zeilen.pop();
      zeilen.filter(Boolean).forEach((z) => controller.enqueue(z));
    },
    flush(controller) {
      if (rest) controller.enqueue(rest);
    }
  });
};

const res = await fetch('/api/events.ndjson');
const zeilen = res.body
  .pipeThrough(new TextDecoderStream())
  .pipeThrough(zeilenSplitter());

for await (const zeile of zeilen) {
  const event = JSON.parse(zeile);
  console.log(event.typ, event.id);
}
login 1 klick 2 logout 3

// Wichtig · Fallstricke

  • Blockgrenzen passen nicht zu Zeilen oder JSON-Grenzen: Der Stream liefert Textstücke von beliebiger Länge. Wenn du Zeilen oder JSON-Objekte brauchst, schalte einen eigenen TransformStream dahinter (siehe NDJSON-Beispiel).
  • Asynchrone Iteration mit for await...of über ReadableStream gibt es in Chrome 124+, Firefox 110+ und Node.js, in Safari aber erst ab 26.4. Für ältere Umgebungen liest du mit stream.getReader() und einer Schleife über reader.read().
  • Mit fatal: true bricht ungültiges UTF-8 den gesamten Stream mit einem TypeError ab. Fang den Fehler also beim Lesen oder mit pipeTo().catch() ab.
  • Der Stream nimmt nur BufferSource an. Schreibst du Zeichenketten oder andere Werte in writable, wird der Stream mit einem TypeError abgebrochen.
  • Die Gegenrichtung (Zeichenketten → UTF-8-Bytes) übernimmt TextEncoderStream. Es kann nur nach UTF-8 kodieren.
  • Kompatibilität: In Firefox erst ab Version 105 verfügbar. Seit Node.js 18 ist das Interface global vorhanden, davor musst du es aus node:stream/web importieren.