Signatur
Beschreibung
Mit controller.error(reason) signalisiert ein TransformStream, dass die Transformation nicht fortgesetzt werden kann. Beide Seiten gehen sofort in den Fehlerzustand über: Die lesbare Seite (readable) liefert bei jedem weiteren read() eine abgelehnte Promise mit reason. Die schreibbare Seite (writable) lehnt weitere write()-Aufrufe ab. Bereits eingereihte, noch nicht gelesene Chunks werden verworfen.
Aufrufen lässt sich die Methode in den Callbacks start(), transform() und flush() des Transformer-Objekts. Typische Fälle sind ungültige Eingabedaten (z. B. kaputtes JSON in einem NDJSON-Parser), überschrittene Größenlimits oder Protokollverletzungen.
Es gibt einen Unterschied zum bloßen Werfen einer Ausnahme in transform(): Ein throw und eine abgelehnte Promise versetzen den Stream ebenfalls in den Fehlerzustand. error() lässt sich aber auch außerhalb des aktuellen Callbacks aufrufen, etwa aus einem Timer oder Event-Handler, wenn man den Controller zwischenspeichert. Soll nur die lesbare Seite sauber beendet werden, nimmt man stattdessen controller.terminate().
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $reason | any | undefined | Der Fehlergrund. Er wird an alle Leser und Schreiber weitergegeben und erscheint z. B. als abgelehnte Promise von reader.read() oder pipeTo(). Üblich ist eine Error-Instanz. |
Rückgabewert
undefined zurück. Der Fehler wird über die Promises der Stream-Seiten gemeldet.Beispiele
Ungültige Zeilen in einem NDJSON-Parser abweisen
const ndjsonParser = () => {
let buffer = '';
return new TransformStream({
transform(chunk, controller) {
buffer += chunk;
const lines = buffer.split('\n');
buffer = lines.pop();
for (const line of lines) {
if (!line.trim()) continue;
try {
controller.enqueue(JSON.parse(line));
} catch {
// Beide Seiten des Streams in den Fehlerzustand setzen
controller.error(new SyntaxError(`Ungültige Zeile: ${line}`));
return;
}
}
}
});
};
const source = new ReadableStream({
start(c) {
c.enqueue('{"id":1}\n');
c.enqueue('kaputt\n');
c.close();
}
});
const reader = source.pipeThrough(ndjsonParser()).getReader();
try {
while (true) {
const { value, done } = await reader.read();
if (done) break;
console.log('Objekt:', value);
}
} catch (err) {
console.error('Abbruch:', err.message);
}
Größenlimit beim Upload durchsetzen
const limitBytes = (max) => {
let total = 0;
return new TransformStream({
transform(chunk, controller) {
total += chunk.byteLength;
if (total > max) {
controller.error(new RangeError(`Limit von ${max} Bytes überschritten`));
return;
}
controller.enqueue(chunk);
}
});
};
const data = new Blob([new Uint8Array(2048)]).stream();
try {
await data.pipeThrough(limitBytes(1024)).pipeTo(new WritableStream());
} catch (err) {
console.log(err.name, '-', err.message);
}
Zeitüberschreitung über gespeicherten Controller
const withTimeout = (ms) => {
let timer;
return new TransformStream({
start(controller) {
// error() funktioniert auch außerhalb der Callbacks
timer = setTimeout(() => controller.error(new Error('Timeout')), ms);
},
transform(chunk, controller) {
controller.enqueue(chunk);
},
flush() {
clearTimeout(timer);
}
});
};
const { readable, writable } = withTimeout(100);
const writer = writable.getWriter();
writer.write('a');
const reader = readable.getReader();
console.log(await reader.read());
try {
await reader.read(); // wartet, bis der Timeout greift
} catch (err) {
console.log('Fehler:', err.message);
}
// Wichtig · Fallstricke
- Unumkehrbar: Ein Stream im Fehlerzustand lässt sich nicht zurücksetzen. Für neue Daten braucht man einen neuen
TransformStream. - Chunks gehen verloren: Chunks, die schon eingereiht, aber noch nicht gelesen wurden, werden verworfen. Leser sehen nur noch den Fehler.
- Nach
error()nicht mehrenqueue()aufrufen: Ein späterescontroller.enqueue()wirft einenTypeError. Deshalb im Beispiel sofortreturn. - Mehrfachaufruf: Weitere Aufrufe von
error()nach dem ersten bewirken nichts. Der erste Fehlergrund bleibt bestehen. - Abgrenzung:
terminate()schließt die lesbare Seite normal und lässt nur die schreibbare Seite fehlschlagen.error()lässt dagegen beide Seiten fehlschlagen. - Unbehandelte Ablehnungen:
pipeTo(),write()undread()lehnen ab. Diese Promises immer mittry/catchoder.catch()behandeln, sonst erscheinen Warnungen über unhandled rejections. - Kompatibilität: Wird von Chrome/Edge 67+, Firefox 102+ und Safari 14.1+ unterstützt. In Node.js steht die Methode ab Version 18 global zur Verfügung, in älteren Versionen über
stream/web.