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

ReadableStream.pipeTo()

Methode

Leitet alle Daten eines <code>ReadableStream</code> in einen <code>WritableStream</code> und gibt ein Promise zurück, das nach Abschluss des Pipings erfüllt oder bei Fehlern abgelehnt wird.

seit JavaScript Baseline: alle modernen Browser (Firefox seit 100) Kategorie: webapi

Signatur

ReadableStream.prototype.pipeTo(destination, options)

Beschreibung

pipeTo() verbindet einen lesbaren Stream mit einem beschreibbaren Ziel. Die Methode liest die Datenstücke (Chunks) nacheinander und schreibt sie ins Ziel. Den Rückstau (Backpressure) berücksichtigt sie dabei automatisch: Ist das Ziel ausgelastet, liest die Methode vorübergehend nicht weiter. Eine eigene Lese- und Schreibschleife mit getReader() und getWriter() brauchen Sie dafür nicht.

Während des Pipings sind beide Streams gesperrt (locked). Sie können also keinen weiteren Reader oder Writer anlegen. Normalerweise gibt das Ende des Quell-Streams das Ende des Ziels vor: Endet die Quelle, wird das Ziel geschlossen. Tritt in der Quelle ein Fehler auf, wird das Ziel abgebrochen. Bricht das Ziel ab, wird die Quelle beendet (cancel). Mit den Optionen preventClose, preventAbort und preventCancel schalten Sie diese Weitergabe einzeln ab.

Typische Einsatzfälle sind das Weiterleiten eines fetch()-Antwortkörpers in eine Datei (File System Access API), in einen eigenen Verarbeitungs-Stream oder in eine Protokollausgabe. Brauchen Sie dagegen eine Kette aus Umwandlungsschritten, ist pipeThrough() mit einem TransformStream meist die bessere Wahl. pipeTo() bildet dann nur das Ende der Kette.

Über die Option signal übergeben Sie ein AbortSignal. Damit lässt sich das Piping jederzeit abbrechen, etwa wenn der Nutzer auf „Abbrechen“ klickt oder eine Zeitüberschreitung eintritt.

Parameter

Name Typ Default Beschreibung
$destination Pflicht WritableStream Das Ziel, in das die Chunks geschrieben werden. Es darf nicht bereits gesperrt sein.
$options Object {} Optionales Objekt, das das Verhalten beim Piping steuert (siehe folgende Einträge).
$options.preventClose boolean false Bei true wird das Ziel nicht geschlossen, wenn die Quelle endet. So können Sie später weitere Daten hineinschreiben.
$options.preventAbort boolean false Bei true führt ein Fehler in der Quelle nicht zum Abbruch des Ziels.
$options.preventCancel boolean false Bei true führt ein Fehler im Ziel nicht zum Beenden (cancel) der Quelle.
$options.signal AbortSignal Signal zum Abbrechen des Pipings. Beim Abbruch werden Quelle und Ziel entsprechend den prevent*-Optionen beendet bzw. abgebrochen, und das Promise wird mit dem Abbruchgrund abgelehnt.

Rückgabewert

Typ
Promise<undefined>
Beschreibung
Ein Promise, das mit undefined erfüllt wird, sobald das Piping vollständig abgeschlossen ist. Bei einem Fehler in Quelle oder Ziel oder bei einem Abbruch über signal wird es mit dem jeweiligen Grund abgelehnt.

Beispiele

Einfaches Piping in einen protokollierenden WritableStream

const quelle = new ReadableStream({
  start(controller) {
    ['Hallo', 'Stream', 'Welt'].forEach((teil) => controller.enqueue(teil));
    controller.close();
  }
});

const ziel = new WritableStream({
  write(chunk) {
    console.log('Empfangen:', chunk);
  },
  close() {
    console.log('Ziel geschlossen');
  }
});

await quelle.pipeTo(ziel);
console.log('Piping fertig');
Empfangen: Hallo Empfangen: Stream Empfangen: Welt Ziel geschlossen Piping fertig

Fetch-Antwort über TransformStream dekodieren und weiterleiten

const response = await fetch('https://example.com/daten.txt');
let zeichen = 0;

await response.body
  .pipeThrough(new TextDecoderStream())
  .pipeTo(new WritableStream({
    write(text) {
      zeichen += text.length;
    },
    close() {
      console.log(`Insgesamt ${zeichen} Zeichen gelesen`);
    }
  }));
Insgesamt 1256 Zeichen gelesen

Piping mit AbortController und Zeitlimit abbrechen

const controller = new AbortController();
setTimeout(() => controller.abort(new Error('Zeitlimit überschritten')), 2000);

const response = await fetch('https://example.com/grosse-datei.bin');

try {
  await response.body.pipeTo(
    new WritableStream({ write(chunk) { /* verarbeiten */ } }),
    { signal: controller.signal }
  );
  console.log('Download komplett');
} catch (err) {
  console.error('Abgebrochen:', err.message);
}
Abgebrochen: Zeitlimit überschritten

Mehrere Quellen nacheinander in ein Ziel schreiben (preventClose)

const erzeuge = (text) => new ReadableStream({
  start(c) { c.enqueue(text); c.close(); }
});

const teile = [];
const ziel = new WritableStream({
  write(chunk) { teile.push(chunk); },
  close() { console.log(teile.join(' ')); }
});

await erzeuge('Teil 1').pipeTo(ziel, { preventClose: true });
await erzeuge('Teil 2').pipeTo(ziel, { preventClose: true });
await ziel.close();
Teil 1 Teil 2

// Wichtig · Fallstricke

  • Gesperrte Streams: Ist die Quelle oder das Ziel bereits gesperrt (locked === true), wird das Promise sofort mit einem TypeError abgelehnt. Das passiert zum Beispiel, wenn schon ein Reader existiert oder ein anderes Piping läuft.
  • Fehler immer behandeln: Ein abgelehntes Promise ohne catch oder try/await erzeugt einen „unhandled rejection“-Fehler. Das gilt auch für einen gewollten Abbruch über signal.
  • Abbruchgrund: Rufen Sie abort() ohne Argument auf, lautet der Grund eine DOMException mit dem Namen AbortError.
  • Ein Stream wird nur einmal gelesen: Nach dem Piping ist die Quelle aufgebraucht. Brauchen Sie die Daten für zwei Ziele, teilen Sie den Stream vorher mit tee().
  • preventClose hält nur das Ziel offen. Sie müssen es danach selbst schließen, sonst wird z. B. eine Datei nie fertig geschrieben.
  • Kompatibilität: Chrome/Edge unterstützen die Methode seit Langem. Firefox unterstützt sie erst seit Version 100, Safari seit 14.1. In Node.js ist sie ab Version 18 global verfügbar (vorher über stream/web).