Signatur
Beschreibung
Die Eigenschaft writable ist die Eingabeseite eines CompressionStream. Sie liefert einen WritableStream, der unkomprimierte Daten als ArrayBuffer, TypedArray (z. B. Uint8Array) oder DataView annimmt. Die komprimierten Bytes erscheinen danach auf der Ausgabeseite CompressionStream.readable.
Zusammen bilden writable und readable ein TransformStream-Paar. Deshalb lässt sich ein CompressionStream direkt an ReadableStream.prototype.pipeThrough() übergeben. Das ist der übliche Weg: Die Pipeline schreibt dann selbst in writable. Direkt über einen Writer (writable.getWriter()) arbeitet man nur, wenn man Daten von Hand und Stück für Stück einspeisen möchte, etwa aus einer Schleife oder aus Ereignissen.
Wichtig: Die komprimierten Daten auf readable sind erst vollständig, wenn die Schreibseite mit writer.close() geschlossen wurde. Erst dann schreibt der Kompressor den Abschluss des Formats (Prüfsumme und Trailer bei gzip). Außerdem sollte man readable gleichzeitig auslesen, denn der Rückstau (Backpressure) kann sonst writer.write() blockieren.
Rückgabewert
WritableStream, der unkomprimierte Chunks (ArrayBuffer, TypedArray, DataView) entgegennimmt. Bei jedem Zugriff kommt dieselbe Instanz zurück.Beispiele
Text manuell über einen Writer mit gzip komprimieren
const compressText = async (text) => {
const cs = new CompressionStream('gzip');
const writer = cs.writable.getWriter();
// Schreiben und Lesen parallel starten, damit der Rückstau nicht blockiert
const resultPromise = new Response(cs.readable).arrayBuffer();
await writer.write(new TextEncoder().encode(text));
await writer.close(); // erst jetzt wird der gzip-Trailer geschrieben
return new Uint8Array(await resultPromise);
};
const gz = await compressText('Hallo Welt! '.repeat(100));
console.log(gz.length, gz[0].toString(16), gz[1].toString(16));
Mehrere Chunks nacheinander schreiben (z. B. Log-Einträge)
const cs = new CompressionStream('deflate');
const writer = cs.writable.getWriter();
const encoder = new TextEncoder();
const blobPromise = new Response(cs.readable).blob();
const logs = [
{ level: 'info', msg: 'Start' },
{ level: 'warn', msg: 'Langsame Antwort' },
{ level: 'info', msg: 'Ende' }
];
for (const entry of logs) {
await writer.ready; // Backpressure respektieren
await writer.write(encoder.encode(JSON.stringify(entry) + '\n'));
}
await writer.close();
const blob = await blobPromise;
console.log('Komprimiert:', blob.size, 'Bytes');
Datei per pipeTo direkt in writable leiten
// <input type="file" id="datei">
const input = document.querySelector('#datei');
input.addEventListener('change', async () => {
const file = input.files[0];
const cs = new CompressionStream('gzip');
const outPromise = new Response(cs.readable).blob();
await file.stream().pipeTo(cs.writable); // schließt writable automatisch
const gz = await outPromise;
console.log(`${file.name}: ${file.size} → ${gz.size} Bytes`);
});
Prüfen, ob writable gesperrt ist
const cs = new CompressionStream('gzip');
console.log(cs.writable instanceof WritableStream);
console.log(cs.writable.locked);
const writer = cs.writable.getWriter();
console.log(cs.writable.locked);
writer.releaseLock();
console.log(cs.writable.locked);
// Wichtig · Fallstricke
- Nur Binärdaten: Strings werden nicht angenommen. Wer einen String schreibt, bekommt einen
TypeError, und der Stream geht in den Fehlerzustand. Text also vorher mitTextEncoderumwandeln oderTextEncoderStreamdavorschalten. - close() nicht vergessen: Ohne
writer.close()endetreadablenie, und die Ausgabe bleibt unvollständig. Bei gzip fehlen dann CRC und Trailer. - Deadlock-Gefahr: Wer mit
awaitgroße Datenmengen schreibt, ohnereadablegleichzeitig auszulesen, kann durch den Rückstau hängen bleiben. Das Lesen daher vor dem Schreiben starten. - Sperre: Es kann immer nur ein Writer oder eine Pipe aktiv sein. Solange
writable.lockedtrueist, werfengetWriter()undpipeTo()einen Fehler. - Abbruch:
writer.abort(grund)bzw. einAbortSignalinpipeTo()versetzt auchreadablein den Fehlerzustand. - Kompatibilität: Seit 2023 in allen großen Browsern verfügbar (Firefox ab 113, Safari ab 16.4), in Node.js global ab Version 18. Das Format
'deflate-raw'wird erst in neueren Versionen unterstützt. Für ältere Umgebungen braucht man einen Fallback wiepakooderfflate.