Firebase-Anwendungen funktionieren auch dann, wenn die Netzwerkverbindung Ihrer App vorübergehend unterbrochen wird. Wir bieten verschiedene Tools zur Überwachung der Präsenz und zur Synchronisierung des lokalen Status mit dem Serverstatus, die in diesem Dokument vorgestellt werden.
Präsenz verwalten
In Echtzeitanwendungen ist es oft nützlich zu erkennen, wann sich Clients verbinden und trennen. Sie können beispielsweise einen Nutzer als „offline“ markieren, wenn die Verbindung des Clients getrennt wird.
Firebase Database-Clients bieten einfache Primitive, mit denen Sie in die Datenbank schreiben können, wenn die Verbindung eines Clients zu den Firebase Database-Servern getrennt wird. Diese Aktualisierungen erfolgen unabhängig davon, ob die Verbindung des Clients ordnungsgemäß getrennt wird oder nicht, Sie können sich also darauf verlassen, dass Daten bereinigt werden, auch wenn eine Verbindung unterbrochen wird oder ein Client abstürzt. Alle Schreibvorgänge, einschließlich Festlegen, Aktualisieren und Entfernen, können nach dem Trennen der Verbindung ausgeführt werden.
Hier ein einfaches Beispiel für das Schreiben von Daten nach dem Trennen der Verbindung mit dem
onDisconnect Primitiv:
Web
import { getDatabase, ref, onDisconnect } from "firebase/database"; const db = getDatabase(); const presenceRef = ref(db, "disconnectmessage"); // Write a string when this client loses connection onDisconnect(presenceRef).set("I disconnected!");
Web
var presenceRef = firebase.database().ref("disconnectmessage"); // Write a string when this client loses connection presenceRef.onDisconnect().set("I disconnected!");
Funktionsweise von „onDisconnect“
Wenn Sie einen onDisconnect()-Vorgang einrichten, wird er auf dem Firebase Realtime Database-Server ausgeführt. Der Server prüft die Sicherheit, um
sicherzustellen, dass der Nutzer das angeforderte Schreibereignis ausführen kann, und informiert
Ihre App, wenn es ungültig ist. Anschließend überwacht der Server die Verbindung. Wenn die Verbindung irgendwann eine Zeitüberschreitung verursacht oder aktiv vom Realtime Database Client geschlossen wird, prüft der Server die Sicherheit ein zweites Mal (um sicherzustellen, dass der Vorgang noch gültig ist) und ruft dann das Ereignis auf.
Ihre App kann den Callback für den Schreibvorgang verwenden
um sicherzustellen, dass der onDisconnect korrekt angehängt wurde:
Web
onDisconnect(presenceRef).remove().catch((err) => { if (err) { console.error("could not establish onDisconnect event", err); } });
Web
presenceRef.onDisconnect().remove((err) => { if (err) { console.error("could not establish onDisconnect event", err); } });
Ein onDisconnect-Ereignis kann auch durch Aufrufen von .cancel() abgebrochen werden:
Web
const onDisconnectRef = onDisconnect(presenceRef); onDisconnectRef.set("I disconnected"); // some time later when we change our minds onDisconnectRef.cancel();
Web
var onDisconnectRef = presenceRef.onDisconnect(); onDisconnectRef.set("I disconnected"); // some time later when we change our minds onDisconnectRef.cancel();
Verbindungsstatus erkennen
Für viele präsenzbezogene Funktionen ist es nützlich, wenn Ihre App
weiß, ob sie online oder offline ist. Firebase Realtime Database
bietet einen speziellen Speicherort unter /.info/connected, der jedes Mal aktualisiert wird, wenn sich der Verbindungsstatus des Firebase Realtime Database-Clients ändert. Hier ein Beispiel:
Web
import { getDatabase, ref, onValue } from "firebase/database"; const db = getDatabase(); const connectedRef = ref(db, ".info/connected"); onValue(connectedRef, (snap) => { if (snap.val() === true) { console.log("connected"); } else { console.log("not connected"); } });
Web
var connectedRef = firebase.database().ref(".info/connected"); connectedRef.on("value", (snap) => { if (snap.val() === true) { console.log("connected"); } else { console.log("not connected"); } });
/.info/connected ist ein boolescher Wert, der nicht
zwischen Realtime Database Clients synchronisiert wird, da er vom Status des Clients
abhängt. Wenn ein Client
/.info/connected als „false“ liest, ist das also keine
Garantie dafür, dass ein anderer Client ebenfalls „false“ liest.
Latenz verarbeiten
Server-Zeitstempel
Die Firebase Realtime Database Server bieten einen Mechanismus zum Einfügen
Zeitstempel, die auf dem Server generiert wurden, als Daten. In Kombination mit
onDisconnect, können Sie so auf einfache Weise zuverlässig den Zeitpunkt erfassen, zu dem die Verbindung eines Realtime Database Clients getrennt wurde:
Web
import { getDatabase, ref, onDisconnect, serverTimestamp } from "firebase/database"; const db = getDatabase(); const userLastOnlineRef = ref(db, "users/joe/lastOnline"); onDisconnect(userLastOnlineRef).set(serverTimestamp());
Web
var userLastOnlineRef = firebase.database().ref("users/joe/lastOnline"); userLastOnlineRef.onDisconnect().set(firebase.database.ServerValue.TIMESTAMP);
Uhrzeitabweichung
`firebase.database.ServerValue.TIMESTAMP` ist zwar viel genauer und für die meisten Lese-/Schreibvorgänge vorzuziehen, aber gelegentlich kann es nützlich sein, die Uhrzeitabweichung des Clients in Bezug auf die firebase.database.ServerValue.TIMESTAMP zu schätzen.Firebase Realtime Database Sie
können einen Callback an den Speicherort /.info/serverTimeOffset
anhängen, um den Wert in Millisekunden abzurufen, den Firebase Realtime Database Clients
zur lokal gemeldeten Zeit (Epochenzeit in Millisekunden) hinzufügen, um die Serverzeit zu schätzen. Die Genauigkeit dieses Offsets kann durch
die Netzwerklatenz beeinträchtigt werden. Es ist daher hauptsächlich nützlich, um
große (> 1 Sekunde) Abweichungen in der Uhrzeit zu erkennen.
Web
import { getDatabase, ref, onValue } from "firebase/database"; const db = getDatabase(); const offsetRef = ref(db, ".info/serverTimeOffset"); onValue(offsetRef, (snap) => { const offset = snap.val(); const estimatedServerTimeMs = new Date().getTime() + offset; });
Web
var offsetRef = firebase.database().ref(".info/serverTimeOffset"); offsetRef.on("value", (snap) => { var offset = snap.val(); var estimatedServerTimeMs = new Date().getTime() + offset; });
Beispiel-App für die Präsenz
Durch die Kombination von Vorgängen zum Trennen der Verbindung mit der Überwachung des Verbindungsstatus und Server-Zeitstempeln können Sie ein System für die Nutzerpräsenz erstellen. In diesem System speichert jeder Nutzer Daten an einem Datenbankspeicherort, um anzugeben, ob ein Realtime Database Client online ist oder nicht. Clients legen diesen Speicherort auf „true“ fest, wenn sie online gehen, und auf einen Zeitstempel, wenn sie die Verbindung trennen. Dieser Zeitstempel gibt an, wann der jeweilige Nutzer zuletzt online war.
Ihre App sollte die Vorgänge zum Trennen der Verbindung in die Warteschlange stellen, bevor ein Nutzer als online markiert wird, um Race-Bedingungen zu vermeiden, falls die Netzwerkverbindung des Clients unterbrochen wird, bevor beide Befehle an den Server gesendet werden können.
Hier ein einfaches System für die Nutzerpräsenz:
Web
import { getDatabase, ref, onValue, push, onDisconnect, set, serverTimestamp } from "firebase/database"; // Since I can connect from multiple devices or browser tabs, we store each connection instance separately // any time that connectionsRef's value is null (i.e. has no children) I am offline const db = getDatabase(); const myConnectionsRef = ref(db, 'users/joe/connections'); // stores the timestamp of my last disconnect (the last time I was seen online) const lastOnlineRef = ref(db, 'users/joe/lastOnline'); const connectedRef = ref(db, '.info/connected'); onValue(connectedRef, (snap) => { if (snap.val() === true) { // We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect) const con = push(myConnectionsRef); // When I disconnect, remove this device onDisconnect(con).remove(); // Add this device to my connections list // this value could contain info about the device or a timestamp too set(con, true); // When I disconnect, update the last time I was seen online onDisconnect(lastOnlineRef).set(serverTimestamp()); } });
Web
// Since I can connect from multiple devices or browser tabs, we store each connection instance separately // any time that connectionsRef's value is null (i.e. has no children) I am offline var myConnectionsRef = firebase.database().ref('users/joe/connections'); // stores the timestamp of my last disconnect (the last time I was seen online) var lastOnlineRef = firebase.database().ref('users/joe/lastOnline'); var connectedRef = firebase.database().ref('.info/connected'); connectedRef.on('value', (snap) => { if (snap.val() === true) { // We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect) var con = myConnectionsRef.push(); // When I disconnect, remove this device con.onDisconnect().remove(); // Add this device to my connections list // this value could contain info about the device or a timestamp too con.set(true); // When I disconnect, update the last time I was seen online lastOnlineRef.onDisconnect().set(firebase.database.ServerValue.TIMESTAMP); } });