Signatur
Beschreibung
Die schreibgeschützte Eigenschaft bufferedAmount eines RTCDataChannel gibt an, wie viele Bytes an Anwendungsdaten derzeit in der Sendewarteschlange liegen. Jeder Aufruf von send() erhöht den Wert um die Größe der Nachricht. Sobald der Browser die Daten an die darunterliegende Transportschicht (SCTP) übergeben hat, sinkt der Wert wieder. Der Overhead von Protokoll und Framing wird dabei nicht mitgezählt.
Die Eigenschaft ist vor allem für die Flusskontrolle (Backpressure) wichtig. Wer große Dateien oder Datenströme in vielen Teilstücken (Chunks) verschickt, sollte nicht einfach in einer Schleife send() aufrufen. Sonst wächst der interne Puffer unkontrolliert, der Speicherverbrauch steigt stark, und manche Browser schließen den Kanal sogar, wenn der Puffer überläuft. Besser prüft man vor jedem Senden bufferedAmount und pausiert, sobald ein Schwellwert überschritten ist.
Zusammen mit bufferedAmountLowThreshold und dem Ereignis bufferedamountlow lässt sich das ereignisgesteuert umsetzen: Sobald bufferedAmount auf den Schwellwert oder darunter fällt, feuert das Ereignis, und die Anwendung kann weitersenden.
Wird der Kanal geschlossen, setzt der Browser den Wert nicht auf 0 zurück. Er zeigt dann weiterhin die Bytes an, die zum Zeitpunkt des Schließens noch nicht gesendet waren.
Rückgabewert
Beispiele
Füllstand des Sendepuffers abfragen
const pc = new RTCPeerConnection();
const channel = pc.createDataChannel('chat');
channel.addEventListener('open', () => {
channel.send('Hallo Welt!');
channel.send(new Uint8Array(1024));
console.log(`Im Puffer: ${channel.bufferedAmount} Bytes`);
});
Große Datei mit Flusskontrolle senden
const CHUNK_SIZE = 16 * 1024; // 16 KiB pro Nachricht
const HIGH_WATER = 1024 * 1024; // ab 1 MiB pausieren
const LOW_WATER = 256 * 1024; // ab 256 KiB weitersenden
const sendFile = async (channel, file) => {
const buffer = await file.arrayBuffer();
channel.bufferedAmountLowThreshold = LOW_WATER;
let offset = 0;
const pump = () => {
while (offset < buffer.byteLength) {
if (channel.bufferedAmount > HIGH_WATER) {
// Warten, bis der Puffer wieder leerer ist
channel.addEventListener('bufferedamountlow', pump, { once: true });
return;
}
channel.send(buffer.slice(offset, offset + CHUNK_SIZE));
offset += CHUNK_SIZE;
}
console.log('Alle Chunks eingereiht');
};
pump();
};
// Verwendung: sendFile(channel, fileInput.files[0]);
Vor dem Schließen warten, bis der Puffer leer ist
const closeWhenDrained = (channel) =>
new Promise((resolve) => {
if (channel.bufferedAmount === 0) {
channel.close();
return resolve();
}
channel.bufferedAmountLowThreshold = 0;
channel.onbufferedamountlow = () => {
channel.onbufferedamountlow = null;
channel.close();
resolve();
};
});
// await closeWhenDrained(channel);
// console.log('Kanal sauber geschlossen');
// Wichtig · Fallstricke
- Eine Null bedeutet nicht, dass die Daten angekommen sind: Bei
0hat der Browser die Daten nur an SCTP übergeben. Ob der Empfänger sie erhalten hat, sagt der Wert nicht. Dafür braucht es eine eigene Empfangsbestätigung auf Anwendungsebene. - Pufferüberlauf: Ältere Chrome-Versionen haben den Kanal geschlossen, sobald etwa 16 MiB im Puffer lagen. Große Datenmengen sollten deshalb immer mit Flusskontrolle gesendet werden. Die Nachrichtengröße sollte bei höchstens 16 bis 64 KiB liegen, damit die Übertragung zwischen verschiedenen Browsern funktioniert.
- Nach dem Schließen: Im Zustand
closingoderclosedwird der Wert nicht zurückgesetzt, er steigt aber auch nicht mehr. Einsend()im Zustandclosedlöst einenInvalidStateErroraus. - Zeichenketten: Gezählt werden die UTF-8-Bytes, nicht die Zeichen.
'ä'zählt also als 2 Bytes. - Kein Polling: Statt den Wert mit
setIntervalregelmäßig abzufragen, ist das Ereignisbufferedamountloweffizienter. - Die Eigenschaft wird in allen aktuellen Browsern unterstützt. In Node.js gibt es sie nur über Bibliotheken wie
node-datachanneloderwrtc.