Signatur
Beschreibung
Ein TextEncoderStream ist ein Transform-Stream: Auf der beschreibbaren Seite (writable) gibt man Zeichenketten hinein, auf der lesbaren Seite (readable) kommen die zugehörigen UTF-8-Bytes als Uint8Array-Blöcke heraus. Die Eigenschaft readable gibt dir genau diese Ausgabeseite als ReadableStream<Uint8Array>.
Meistens greift man nicht direkt auf readable zu. Stattdessen reicht man den ganzen TextEncoderStream an ReadableStream.prototype.pipeThrough() weiter, und das Ergebnis von pipeThrough() ist dann genau dieser readable-Stream. Direkt brauchst du die Eigenschaft, wenn du selbst schreibst (über writable.getWriter()) und die Bytes separat weiterverarbeiten willst, zum Beispiel als Request-Body für fetch(), für einen CompressionStream oder für eine Datei-Schreiboperation.
Die Kodierung ist immer UTF-8, andere Zeichensätze gibt es nicht. Anders als ein einfaches TextEncoder.encode() in einer Schleife kommt der Stream mit Surrogatpaaren zurecht, die auf zwei Blöcke verteilt sind: Ein einzelnes hohes Surrogat am Ende eines Blocks wird zurückgehalten, bis der nächste Block ankommt.
Rückgabewert
Uint8Array mit UTF-8-Bytes. Bei jedem Zugriff kommt dasselbe Objekt zurück.Beispiele
Zeichenketten schreiben und Bytes direkt lesen
const encoder = new TextEncoderStream();
const writer = encoder.writable.getWriter();
const reader = encoder.readable.getReader();
// Schreiben und Lesen laufen parallel, sonst droht Rückstau (Backpressure)
const writing = (async () => {
await writer.write('Hallo ');
await writer.write('Wält');
await writer.close();
})();
const chunks = [];
while (true) {
const { value, done } = await reader.read();
if (done) break;
chunks.push(value);
}
await writing;
console.log(chunks.map((c) => Array.from(c)));
Typischer Einsatz mit pipeThrough()
const textStream = new ReadableStream({
start(controller) {
controller.enqueue('Zeile 1\n');
controller.enqueue('Zeile 2 – mit Umlaut ü\n');
controller.close();
}
});
// pipeThrough() gibt encoder.readable zurück
const byteStream = textStream.pipeThrough(new TextEncoderStream());
const buffer = await new Response(byteStream).arrayBuffer();
console.log(buffer.byteLength);
Text kodieren, komprimieren und hochladen
const encoder = new TextEncoderStream();
// readable weiter in einen CompressionStream leiten
const gzipped = encoder.readable.pipeThrough(new CompressionStream('gzip'));
const writer = encoder.writable.getWriter();
writer.write(JSON.stringify({ log: 'Ereignis', ts: Date.now() }));
writer.close();
// Streaming-Upload (Chromium: duplex: 'half' ist Pflicht)
const response = await fetch('/api/logs', {
method: 'POST',
headers: { 'Content-Encoding': 'gzip' },
body: gzipped,
duplex: 'half'
});
console.log(response.status);
// Wichtig · Fallstricke
- Schreibgeschützt: Wenn du
readableetwas zuweist, passiert nichts. Im Strict Mode gibt es einenTypeError, weil nur ein Getter existiert. - Sperre: Sobald
getReader()aufgerufen oder der Stream mitpipeTo()/pipeThrough()verbunden ist, ist er gesperrt (readable.locked === true). Ein zweiter Leser führt zu einemTypeError. Mehrere Konsumenten bekommst du nur übertee(). - Rückstau (Backpressure): Wenn du auf
writer.write()wartest, ohne dass jemand parallel ausreadableliest, kann das Programm hängen bleiben. Lies deshalb gleichzeitig oder verbinde die Streams überpipeThrough(). - Die Blockgrenzen der Ausgabe folgen den Schreibaufrufen. Leere Zeichenketten erzeugen keinen Block. Nicht-String-Werte werden vorher in Strings umgewandelt.
- Kompatibilität: Firefox unterstützt die Eigenschaft erst ab Version 105. Streaming-Request-Bodies mit
fetch()gehen derzeit nur in Chromium-Browsern und brauchenduplex: 'half'.