Firebase-Anwendungen funktionieren auch dann, wenn die Netzwerkverbindung Ihrer App vorübergehend unterbrochen wird. Wir bieten verschiedene Tools zum Überwachen der Anwesenheit und zum Synchronisieren des lokalen Status mit dem Serverstatus, die in diesem Dokument vorgestellt werden.
Präsenz verwalten
Bei Echtzeitanwendungen ist es oft nützlich, zu erkennen, wann Clients eine Verbindung herstellen und trennen. Sie können beispielsweise einen Nutzer als „offline“ markieren, wenn die Verbindung zu seinem Client getrennt wird.
Firebase-Datenbankclients bieten einfache Primitiven, mit denen Sie in die Datenbank schreiben können, wenn ein Client die Verbindung zu den Firebase-Datenbankservern trennt. Diese Aktualisierungen erfolgen unabhängig davon, ob die Verbindung zum Client ordnungsgemäß getrennt wird. Sie können sich also darauf verlassen, dass Daten auch dann bereinigt werden, wenn eine Verbindung unterbrochen wird oder ein Client abstürzt. Alle Schreibvorgänge, einschließlich des Festlegens, Aktualisierens und Entfernens, können nach dem Trennen der Verbindung ausgeführt werden.
Hier ist ein einfaches Beispiel für das Schreiben von Daten nach dem Trennen der Verbindung mit dem onDisconnect
-Primitive:
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!");
So funktioniert „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. Der Server überwacht dann die Verbindung. Wenn die Verbindung zu einem beliebigen Zeitpunkt das Zeitlimit überschreitet oder vom Realtime Database-Client aktiv 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 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 Funktionen, die mit der Anwesenheit zusammenhängen, ist es nützlich, wenn Ihre App weiß, wann 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, bedeutet das nicht, dass ein anderer Client ebenfalls „false“ liest.
Latenz bearbeiten
Server-Zeitstempel
Die Firebase Realtime Database-Server bieten einen Mechanismus zum Einfügen von Zeitstempeln, die auf dem Server generiert werden, als Daten. Diese Funktion bietet in Kombination mit onDisconnect
eine einfache Möglichkeit, die Zeit zu erfassen, zu der ein Realtime Database-Client die Verbindung getrennt hat:
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);
Clock Skew
firebase.database.ServerValue.TIMESTAMP
ist zwar viel genauer und für die meisten Lese-/Schreibvorgänge vorzuziehen, aber es kann gelegentlich nützlich sein, die Zeitabweichung des Clients in Bezug auf die Server von Firebase Realtime Database zu schätzen. Sie können einen Callback an den Speicherort /.info/serverTimeOffset
anhängen, um den Wert in Millisekunden abzurufen, den Firebase Realtime Database-Clients der 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. Er ist daher hauptsächlich nützlich, um große (> 1 Sekunde) Abweichungen bei 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 Anwesenheitserkennung
Durch die Kombination von Trennungsvorgängen mit der Überwachung des Verbindungsstatus und Serverzeitstempeln können Sie ein System zur Nutzerpräsenz erstellen. In diesem System speichert jeder Nutzer Daten an einem Datenbankstandort, um anzugeben, ob ein Realtime Database-Client online ist. Clients legen diesen Standort auf „true“ fest, wenn sie online gehen, und auf einen Zeitstempel, wenn sie die Verbindung trennen. Dieser Zeitstempel gibt an, wann der angegebene Nutzer zuletzt online war.
Ihre App sollte die Trennungsvorgänge in die Warteschlange stellen, bevor ein Nutzer als online markiert wird. So lassen sich Race-Bedingungen vermeiden, falls die Netzwerkverbindung des Clients verloren geht, bevor beide Befehle an den Server gesendet werden können.
Hier ist ein einfaches System zur Erkennung der Anwesenheit von Nutzern:
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); } });