Start · Sprachen · JavaScript · Referenz · RTCStatsReport.forEach()

RTCStatsReport.forEach()

Methode

Ruft eine Funktion einmal für jedes Schlüssel/Wert-Paar eines <code>RTCStatsReport</code> auf, in der Reihenfolge, in der die Einträge eingefügt wurden.

seit JavaScript Baseline: alle modernen Browser (Chrome 58+, Firef Kategorie: webapi

Signatur

RTCStatsReport.prototype.forEach(callbackFn, thisArg)

Beschreibung

RTCStatsReport ist ein schreibgeschütztes, Map-ähnliches Objekt. Es enthält die Statistiken einer WebRTC-Verbindung. Jeder Schlüssel ist die eindeutige id eines Statistikobjekts. Der zugehörige Wert ist ein Statistik-Wörterbuch wie RTCInboundRtpStreamStats, RTCOutboundRtpStreamStats, RTCIceCandidatePairStats oder RTCTransportStats. Mit forEach() gehen Sie alle diese Einträge nacheinander durch.

Die Methode verhält sich wie Map.prototype.forEach(). Die Rückruffunktion erhält zuerst den Wert (das Statistikobjekt), dann den Schlüssel (die ID) und zuletzt den Bericht selbst. Meist prüft man in der Rückruffunktion die Eigenschaft type, um bestimmte Statistiken herauszufiltern, zum Beispiel "inbound-rtp" für empfangene Medienströme oder "candidate-pair" für die aktive ICE-Verbindung.

Einen RTCStatsReport bekommen Sie über das Promise von RTCPeerConnection.getStats(), RTCRtpSender.getStats() oder RTCRtpReceiver.getStats(). Typische Einsatzzwecke sind Qualitätsanzeigen (Bitrate, Paketverlust, Jitter, Round-Trip-Time), Fehlersuche und Telemetrie.

Parameter

Name Typ Default Beschreibung
$callbackFn Pflicht (value: object, key: string, report: RTCStatsReport) => void Wird für jeden Eintrag aufgerufen. Sie erhält value (das Statistikobjekt), key (die ID als String) und report (den durchlaufenen Bericht).
$thisArg any undefined Wert, der beim Aufruf von callbackFn als this gilt. Bei Pfeilfunktionen hat er keine Wirkung.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Die Methode dient nur dazu, die Einträge durchzugehen.

Beispiele

Alle Statistiktypen einer Verbindung auflisten

const pc = new RTCPeerConnection();
pc.createDataChannel('probe');
await pc.setLocalDescription(await pc.createOffer());

const report = await pc.getStats();
report.forEach((stats, id) => {
  console.log(`${stats.type.padEnd(20)} ${id}`);
});
peer-connection PC_... data-channel D1 ... (je nach Browser und Verbindungszustand)

Paketverlust und Jitter eingehender Videoströme auswerten

const logInboundVideo = async (pc) => {
  const report = await pc.getStats();
  report.forEach((stats) => {
    if (stats.type === 'inbound-rtp' && stats.kind === 'video') {
      const total = stats.packetsReceived + stats.packetsLost;
      const lossPct = total ? (stats.packetsLost / total) * 100 : 0;
      console.log(`Verlust: ${lossPct.toFixed(2)} %, Jitter: ${(stats.jitter * 1000).toFixed(1)} ms`);
    }
  });
};

// Alle 2 Sekunden abfragen
setInterval(() => logInboundVideo(pc), 2000);
Verlust: 0.35 %, Jitter: 4.2 ms

Aktives ICE-Kandidatenpaar mit Referenz auf den Report finden

const getRoundTripTime = async (pc) => {
  const report = await pc.getStats();
  let rtt = null;
  report.forEach((stats, id, rep) => {
    if (stats.type === 'transport' && stats.selectedCandidatePairId) {
      // Über den dritten Parameter auf andere Einträge zugreifen
      const pair = rep.get(stats.selectedCandidatePairId);
      rtt = pair?.currentRoundTripTime ?? null;
    }
  });
  return rtt;
};

console.log('RTT (s):', await getRoundTripTime(pc));
RTT (s): 0.042

Ausgehende Bitrate mit thisArg sammeln

const collector = { bytes: 0 };
const report = await pc.getStats();
report.forEach(function (stats) {
  if (stats.type === 'outbound-rtp') this.bytes += stats.bytesSent;
}, collector);
console.log(`Gesendet: ${collector.bytes} Bytes`);
Gesendet: 1843201 Bytes

// Wichtig · Fallstricke

  • Reihenfolge der Argumente: Wie bei Map kommt zuerst der Wert und dann der Schlüssel, also (stats, id) und nicht umgekehrt.
  • forEach() lässt sich weder mit break noch mit return vorzeitig beenden. Wenn Sie früh abbrechen wollen, verwenden Sie for (const [id, stats] of report) oder report.values().
  • Asynchrone Rückruffunktionen werden nicht abgewartet. Ein await in der Rückruffunktion hält die Schleife nicht an.
  • Ein Bericht ist nur eine Momentaufnahme. Er aktualisiert sich nicht selbst. Kumulierte Zähler wie bytesReceived ergeben erst eine Rate, wenn Sie zwei Berichte vergleichen, deren Differenz bilden und durch die Differenz der timestamp-Werte teilen.
  • Welche Statistiktypen und Felder vorhanden sind, hängt vom Browser ab. Ältere Chrome-Versionen kennen zum Beispiel noch "track"-Statistiken, Firefox liefert manche Felder nicht. Greifen Sie deshalb defensiv zu, etwa mit ?. und ??.
  • Der Bericht ist schreibgeschützt. Methoden wie set() oder delete() gibt es nicht.
  • Die Werte können Rückschlüsse auf das Netzwerk zulassen, etwa über IP-Adressen in Kandidaten-Statistiken. Übermitteln Sie Telemetriedaten deshalb nur datenschutzkonform.