Start · Sprachen · JavaScript · Referenz · RTCDataChannel: closing

RTCDataChannel: closing

Ereignis

Wird an einem <code>RTCDataChannel</code> ausgelöst, wenn sein Datentransport zu schließen beginnt und <code>readyState</code> auf <code>"closing"</code> wechselt.

seit JavaScript WebRTC 1.0 – Chromium-Browser und Safari; in Firef Kategorie: webapi

Signatur

dataChannel.addEventListener("closing", handler)

Beschreibung

Das Ereignis closing wird an einem RTCDataChannel ausgelöst, sobald der zugrunde liegende Datentransport (ein SCTP-Stream) zu schließen beginnt. Dabei wechselt readyState von "open" auf "closing". Ab diesem Zeitpunkt können Sie keine neuen Nachrichten mehr mit send() verschicken. Nachrichten, die schon in der Warteschlange stehen (bufferedAmount), werden aber möglicherweise noch übertragen. Sobald der Kanal vollständig geschlossen ist, folgt das Ereignis close.

Sie können einen Handler auf zwei Arten registrieren: mit addEventListener("closing", handler) oder über die Eigenschaft onclosing. Das Ereignisobjekt ist ein einfaches Event ohne zusätzliche Eigenschaften. Es steigt nicht auf (bubbelt nicht) und lässt sich nicht abbrechen.

Wofür ist das nützlich? Mit closing erfahren Sie früh, dass die Verbindung abgebaut wird. Das ist vor allem wichtig, wenn die Gegenseite den Kanal schließt. So können Sie zum Beispiel die Oberfläche anpassen („Verbindung wird getrennt …“), Eingabefelder sperren oder den Zustand Ihrer Anwendung sichern, bevor das endgültige close eintrifft.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname, immer "closing".
$handler Pflicht (event: Event) => void Die Rückruffunktion. Sie erhält ein einfaches Event-Objekt; event.target ist der betroffene RTCDataChannel.
$options boolean | AddEventListenerOptions false Optionale Einstellungen für addEventListener, etwa { once: true } oder { signal }.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Die Rückruffunktion erhält ein Event-Objekt.

Beispiele

Schließen der Gegenseite mit addEventListener erkennen (lokale Schleife)

// Zwei lokale Peers, die direkt miteinander verbunden werden
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();
pc1.onicecandidate = (e) => e.candidate && pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = (e) => e.candidate && pc1.addIceCandidate(e.candidate);

const sender = pc1.createDataChannel('chat');

pc2.addEventListener('datachannel', ({ channel }) => {
  channel.addEventListener('closing', () => {
    console.log('closing – readyState:', channel.readyState);
  });
  channel.addEventListener('close', () => {
    console.log('close – readyState:', channel.readyState);
  });
});

sender.addEventListener('open', () => {
  // Die Gegenseite schließt den Kanal → auf pc2 wird closing ausgelöst
  setTimeout(() => sender.close(), 500);
});

const offer = await pc1.createOffer();
await pc1.setLocalDescription(offer);
await pc2.setRemoteDescription(offer);
const answer = await pc2.createAnswer();
await pc2.setLocalDescription(answer);
await pc1.setRemoteDescription(answer);
closing – readyState: closing close – readyState: closed

Oberfläche über onclosing sperren

const setupChannelUi = (channel) => {
  const input = document.querySelector('#message');
  const status = document.querySelector('#status');

  channel.onopen = () => {
    input.disabled = false;
    status.textContent = 'Verbunden';
  };

  // Früh reagieren: ab jetzt schlägt send() fehl
  channel.onclosing = () => {
    input.disabled = true;
    status.textContent = 'Verbindung wird getrennt …';
  };

  channel.onclose = () => {
    status.textContent = 'Getrennt';
  };
};

const pc = new RTCPeerConnection();
pc.ondatachannel = ({ channel }) => setupChannelUi(channel);

Listener mit removeEventListener wieder entfernen

const pc = new RTCPeerConnection();
const channel = pc.createDataChannel('telemetry');

const onClosing = (event) => {
  console.warn(`Kanal "${event.target.label}" wird geschlossen`);
};

channel.addEventListener('closing', onClosing);

// Später, z. B. wenn die Komponente entfernt wird:
channel.removeEventListener('closing', onClosing);
// Alternativ bei Nutzung der Property:
channel.onclosing = null;

// Wichtig · Fallstricke

  • Wann wird das Ereignis ausgelöst? Laut Spezifikation feuert closing nur, wenn das Schließen nicht durch einen Aufruf von close() auf demselben Kanal ausgelöst wurde. Typische Fälle sind: Die Gegenseite schließt den Kanal, oder der Transport wird zurückgesetzt. Rufen Sie selbst close() auf, springt readyState zwar direkt auf "closing", aber auf dieser Seite folgt nur noch close.
  • Browser-Unterstützung: Chromium-basierte Browser (Chrome, Edge, Opera) und Safari unterstützen das Ereignis. Firefox unterstützt closing bzw. onclosing bisher nicht. Verlassen Sie sich deshalb nie allein darauf, sondern werten Sie immer auch close aus. Sie können die Unterstützung so prüfen: 'onclosing' in RTCDataChannel.prototype.
  • Nach closing wirft send() einen InvalidStateError. Prüfen Sie deshalb vor dem Senden channel.readyState === "open".
  • Das Ereignis steigt nicht auf und lässt sich nicht abbrechen: preventDefault() kann das Schließen nicht verhindern.
  • Wird die ganze RTCPeerConnection mit pc.close() geschlossen, werden die Datenkanäle ohne closing-Ereignis sofort geschlossen.