Start · Sprachen · JavaScript · Referenz · ReadableStream.pipeThrough()

ReadableStream.pipeThrough()

Methode

Leitet einen <code>ReadableStream</code> durch einen Transform-Stream (Paar aus <code>writable</code> und <code>readable</code>) und gibt dessen lesbare Seite zurück, sodass sich Aufrufe verketten lassen.

seit JavaScript Baseline: alle modernen Browser (Chrome 59+, Firef Kategorie: webapi

Signatur

ReadableStream.prototype.pipeThrough(transformStream, options)

Beschreibung

pipeThrough() verbindet den aktuellen ReadableStream mit der schreibbaren Seite (writable) eines Transform-Paars und gibt dessen lesbare Seite (readable) zurück. Da der Rückgabewert wieder ein ReadableStream ist, lassen sich mehrere Transformationen elegant hintereinanderschalten – ähnlich wie Pipes in der Unix-Shell.

Typische Einsatzgebiete sind das Dekodieren von Bytes zu Text mit TextDecoderStream, das (De-)Komprimieren mit CompressionStream/DecompressionStream sowie eigene Verarbeitungsschritte über TransformStream, etwa das Zerlegen eines Textstroms in Zeilen oder das Parsen von NDJSON. Die Daten werden dabei stückweise (in Chunks) verarbeitet, ohne dass der gesamte Inhalt im Speicher gehalten werden muss.

Während der Weiterleitung ist der Quell-Stream gesperrt (locked === true); man kann also keinen eigenen Reader mehr darauf holen. Die eigentliche Übertragung läuft intern über pipeTo() ab, Rückstau (Backpressure) wird automatisch berücksichtigt. Über die options steuert man, wie Abbruch, Fehler und Schließen zwischen den Streams weitergegeben werden.

Parameter

Name Typ Default Beschreibung
$transformStream Pflicht { writable: WritableStream, readable: ReadableStream } | TransformStream Ein Objekt mit einer writable- und einer readable-Eigenschaft, z. B. ein TransformStream, TextDecoderStream oder CompressionStream. Daten werden in writable geschrieben und aus readable gelesen.
$options Object {} Optionale Einstellungen für die Weiterleitung.
$options.preventClose boolean false Bei true wird die schreibbare Seite nicht geschlossen, wenn der Quell-Stream endet.
$options.preventAbort boolean false Bei true führt ein Fehler im Quell-Stream nicht zum Abbruch der schreibbaren Seite.
$options.preventCancel boolean false Bei true wird der Quell-Stream bei einem Fehler auf der schreibbaren Seite nicht abgebrochen (cancel).
$options.signal AbortSignal Ein AbortSignal, mit dem die laufende Weiterleitung abgebrochen werden kann.

Rückgabewert

Typ
ReadableStream
Beschreibung
Die readable-Seite des übergebenen Transform-Paars – bereit zum Lesen oder für weitere pipeThrough()-Aufrufe.

Beispiele

Fetch-Antwort als Text stückweise lesen

const response = await fetch('/api/log.txt');

// Bytes -> Text dekodieren
const textStream = response.body.pipeThrough(new TextDecoderStream());

const reader = textStream.getReader();
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  console.log('Chunk:', value);
}
Chunk: <erste Textportion> Chunk: <nächste Textportion> ...

Eigene Transformation: Text in Großbuchstaben

const upperCase = new TransformStream({
  transform(chunk, controller) {
    controller.enqueue(chunk.toUpperCase());
  }
});

const source = new ReadableStream({
  start(controller) {
    controller.enqueue('hallo ');
    controller.enqueue('welt');
    controller.close();
  }
});

const result = await new Response(source.pipeThrough(upperCase)).text();
console.log(result);
HALLO WELT

Verkettung: gzip-Datei entpacken und zeilenweise verarbeiten

const splitLines = () => {
  let buffer = '';
  return new TransformStream({
    transform(chunk, controller) {
      buffer += chunk;
      const lines = buffer.split('\n');
      buffer = lines.pop();
      lines.forEach((line) => controller.enqueue(line));
    },
    flush(controller) {
      if (buffer) controller.enqueue(buffer);
    }
  });
};

const response = await fetch('/data/events.ndjson.gz');
const lines = response.body
  .pipeThrough(new DecompressionStream('gzip'))
  .pipeThrough(new TextDecoderStream())
  .pipeThrough(splitLines());

for await (const line of lines) { // async Iteration: nicht in Safari < 18
  const event = JSON.parse(line);
  console.log(event.type);
}
click scroll ...

Weiterleitung per AbortSignal abbrechen

const controller = new AbortController();
const response = await fetch('/api/stream');

const textStream = response.body.pipeThrough(new TextDecoderStream(), {
  signal: controller.signal
});

// Nach 2 Sekunden abbrechen
setTimeout(() => controller.abort(), 2000);

try {
  for await (const chunk of textStream) console.log(chunk);
} catch (err) {
  console.log('Abgebrochen:', err.name);
}
... Abgebrochen: AbortError

// Wichtig · Fallstricke

  • Sperre: Ist der Quell-Stream bereits gesperrt (locked) oder die writable-Seite gesperrt, wirft pipeThrough() sofort einen TypeError. Ein Stream kann nur einmal weitergeleitet werden – für mehrere Verbraucher vorher tee() nutzen.
  • Fehlerbehandlung: Das intern von pipeTo() gelieferte Promise ist nicht zugänglich. Fehler zeigen sich erst beim Lesen des zurückgegebenen Streams – dort also try/catch verwenden.
  • Kein Mehrfach-Ende: Ohne preventClose wird die writable-Seite beim Ende der Quelle geschlossen; so lassen sich Transform-Streams nicht wiederverwenden. Pro Pipeline immer neue Instanzen erzeugen.
  • Kompatibilität: In allen modernen Browsern verfügbar; Firefox unterstützt die Methode erst ab Version 102. for await...of über ReadableStream fehlt in Safari vor 18 – dort getReader() verwenden. In Node.js ab 16.5 über stream/web, ab 18 global.