Start · Sprachen · JavaScript · Referenz · RTCDataChannel: bufferedamountlow

RTCDataChannel: bufferedamountlow

Ereignis

Wird ausgelöst, wenn <code>bufferedAmount</code> eines <code>RTCDataChannel</code> von oberhalb auf höchstens <code>bufferedAmountLowThreshold</code> fällt – ideal zur Flusssteuerung beim Senden.

seit JavaScript Baseline: alle modernen Browser (Chrome, Edge, Fir Kategorie: webapi

Signatur

dataChannel.addEventListener("bufferedamountlow", handler)

Beschreibung

Das Ereignis bufferedamountlow wird an einen RTCDataChannel gesendet, sobald die Anzahl der Bytes im ausgehenden Puffer (bufferedAmount) von einem Wert oberhalb auf einen Wert kleiner oder gleich bufferedAmountLowThreshold sinkt. Es ist ein einfaches Event ohne zusätzliche Eigenschaften, bubbelt nicht und ist nicht abbrechbar.

Hauptzweck ist die Flusssteuerung (Backpressure): Wer große Datenmengen – etwa Dateien in Blöcken – über einen Datenkanal überträgt, darf send() nicht beliebig schnell aufrufen. Ein überfüllter Puffer erhöht den Speicherverbrauch und kann in manchen Browsern sogar zum Schließen des Kanals führen. Stattdessen pausiert man das Senden, sobald bufferedAmount eine Obergrenze überschreitet, und setzt es fort, wenn bufferedamountlow eintrifft.

Registrieren lässt sich der Handler per addEventListener("bufferedamountlow", handler) oder über die Eigenschaft onbufferedamountlow. Der Standardwert von bufferedAmountLowThreshold ist 0; dann feuert das Ereignis erst, wenn der Puffer komplett geleert ist. Für einen kontinuierlichen Datenfluss sollte man einen höheren Schwellwert (z. B. 64 KiB) setzen, damit der Puffer nie ganz leerläuft.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "bufferedamountlow".
$handler Pflicht (event: Event) => void Callback, der ein generisches Event erhält; event.target ist der betroffene RTCDataChannel.
$options boolean | AddEventListenerOptions false Optionale Listener-Optionen wie once oder signal.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Der Handler erhält ein Event ohne zusätzliche Daten.

Beispiele

Datei in Blöcken mit Flusssteuerung senden

const CHUNK_SIZE = 16 * 1024;        // 16 KiB pro Nachricht
const HIGH_WATER = 1024 * 1024;      // 1 MiB: Senden pausieren

const sendFile = async (channel, file) => {
  channel.binaryType = 'arraybuffer';
  channel.bufferedAmountLowThreshold = 256 * 1024; // bei 256 KiB fortsetzen
  const buffer = await file.arrayBuffer();
  let offset = 0;

  const pump = () => {
    while (offset < buffer.byteLength) {
      if (channel.bufferedAmount > HIGH_WATER) {
        // Warten, bis der Puffer abgebaut ist
        channel.addEventListener('bufferedamountlow', pump, { once: true });
        return;
      }
      channel.send(buffer.slice(offset, offset + CHUNK_SIZE));
      offset += CHUNK_SIZE;
    }
    console.log('Datei vollständig in den Puffer gegeben');
  };

  pump();
};

// Verwendung: channel ist ein offener RTCDataChannel
// sendFile(channel, fileInput.files[0]);
Datei vollständig in den Puffer gegeben

Handler über die on-Property setzen und wieder entfernen

const pc = new RTCPeerConnection();
const channel = pc.createDataChannel('chat');
channel.bufferedAmountLowThreshold = 64 * 1024;

channel.onbufferedamountlow = (event) => {
  console.log('Puffer niedrig:', event.target.bufferedAmount, 'Bytes');
};

// Später deaktivieren
channel.onbufferedamountlow = null;

Promise-basiertes Warten mit addEventListener/removeEventListener

const waitForDrain = (channel) =>
  new Promise((resolve, reject) => {
    if (channel.bufferedAmount <= channel.bufferedAmountLowThreshold) {
      resolve();
      return;
    }
    const onLow = () => { cleanup(); resolve(); };
    const onClose = () => { cleanup(); reject(new Error('Kanal geschlossen')); };
    const cleanup = () => {
      channel.removeEventListener('bufferedamountlow', onLow);
      channel.removeEventListener('close', onClose);
    };
    channel.addEventListener('bufferedamountlow', onLow);
    channel.addEventListener('close', onClose);
  });

// In einer async-Sendeschleife:
// for (const chunk of chunks) {
//   if (channel.bufferedAmount > 1_000_000) await waitForDrain(channel);
//   channel.send(chunk);
// }

// Wichtig · Fallstricke

  • Nur beim Übergang: Das Ereignis feuert ausschließlich, wenn bufferedAmount von über auf höchstens den Schwellwert fällt. Ist der Puffer beim Registrieren schon niedrig, kommt kein Ereignis – vorher immer bufferedAmount prüfen, sonst hängt die Sendeschleife.
  • Standard-Schwellwert 0: Mit dem Standardwert läuft der Puffer vollständig leer, bevor weitergesendet wird – das kostet Durchsatz. Einen sinnvollen Wert (z. B. 64–256 KiB) setzen.
  • Nachrichtengröße: Einzelne send()-Aufrufe sollten klein bleiben (ca. 16 KiB für maximale Kompatibilität zwischen Browsern), auch wenn RTCSctpTransport.maxMessageSize größere Werte erlaubt.
  • Puffer-Überlauf: Überschreitet der Puffer das interne Browser-Limit (in Chrome früher ca. 16 MiB), wirft send() einen OperationError bzw. der Kanal wird geschlossen.
  • Auch auf close reagieren, damit wartende Promises nicht ewig offen bleiben.
  • Kompatibilität: in allen aktuellen Browsern unterstützt; in Node.js nur über Bibliotheken wie node-datachannel oder wrtc.