הפעלת יכולות לא מקוונות ב- JavaScript

יישומי Firebase עובדים גם אם האפליקציה שלך מאבדת את חיבור הרשת שלה באופן זמני. אנו מספקים מספר כלים לניטור נוכחות וסנכרון מצב מקומי עם מצב שרת, המוצגים במסמך זה.

ניהול נוכחות

ביישומים בזמן אמת לעתים קרובות שימושי לזהות מתי לקוחות מתחברים ומתנתקים. לדוגמה, ייתכן שתרצה לסמן משתמש כ'לא מקוון 'כאשר הלקוח שלו מתנתק.

לקוחות מסד הנתונים של Firebase מספקים פרימיטיבים פשוטים שבאמצעותם תוכל לכתוב למסד הנתונים כאשר לקוח מתנתק משרתי מסד הנתונים של Firebase. עדכונים אלה מתרחשים בין אם הלקוח מתנתק בצורה נקייה ובין אם לאו, כך שתוכל לסמוך עליהם כדי לנקות נתונים גם אם החיבור יופסק או שהלקוח קורס. כל פעולות הכתיבה, כולל הגדרה, עדכון והסרה, ניתנות לביצוע לאחר ניתוק.

הנה דוגמה פשוטה של כתיבת נתונים על ניתוק באמצעות onDisconnect פרימיטיבית:

גרסת אינטרנט 9

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!");

גרסת אינטרנט 8

var presenceRef = firebase.database().ref("disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnect().set("I disconnected!");

כיצד פועל onDisconnect

כשאתה להקים onDisconnect() פעולה, הפעולה חייה בשרת מסד Firebase זמן האמת. השרת בודק את האבטחה כדי לוודא שהמשתמש יכול לבצע את אירוע הכתיבה המבוקש, ומודיע לאפליקציה שלך אם היא לא חוקית. השרת עוקב אחר החיבור. אם בשלב מסוים החיבור פסק זמן, או נסגר באופן פעיל על ידי לקוח מסד הנתונים בזמן אמת, השרת בודק את האבטחה בפעם השנייה (כדי לוודא שהפעולה עדיין בתוקף) ולאחר מכן מפעיל את האירוע.

היישום יכול להשתמש התקשרות על פעולת הכתיבה כדי להבטיח את onDisconnect צורף נכון:

גרסת אינטרנט 9

onDisconnect(presenceRef).remove().catch((err) => {
  if (err) {
    console.error("could not establish onDisconnect event", err);
  }
});

גרסת אינטרנט 8

presenceRef.onDisconnect().remove((err) => {
  if (err) {
    console.error("could not establish onDisconnect event", err);
  }
});

onDisconnect האירוע יכול גם יבוטל על ידי התקשרות .cancel() :

גרסת אינטרנט 9

const onDisconnectRef = onDisconnect(presenceRef);
onDisconnectRef.set("I disconnected");
// some time later when we change our minds
onDisconnectRef.cancel();

גרסת אינטרנט 8

var onDisconnectRef = presenceRef.onDisconnect();
onDisconnectRef.set("I disconnected");
// some time later when we change our minds
onDisconnectRef.cancel();

זיהוי מצב חיבור

לתכונות רבות הקשורות לנוכחות, כדאי לאפליקציה שלך לדעת מתי היא מקוונת או לא מקוונת. מסד Firebase זמן אמת מספק מיקום מיוחד /.info/connected המתעדכן כל הזמן משתנה מצב החיבור של הלקוח מסד Firebase זמן אמת. הנה דוגמה:

גרסת אינטרנט 9

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");
  }
});

גרסת אינטרנט 8

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 הוא ערך בוליאני אשר אינו מסונכרן בין לקוחות מסד זמן אמת בגלל הערך תלוי במצב של הלקוח. במילים אחרות, אם לקוח אחד לא קורא /.info/connected כמו שקר, זו אינה ערובה כי לקוח נפרד גם יקראו שווא.

טיפול באיחור

חותמות זמן של השרת

שרתי מסד הנתונים של Firebase Realtime מספקים מנגנון להוספת חותמות זמן שנוצרות בשרת כנתונים. תכונה זו, בשילוב עם onDisconnect , מספקת דרך קלה לעשות מהימנה לב לשעה שבה לקוח מסד זמן אמת מנותק:

גרסת אינטרנט 9

import { getDatabase, ref, onDisconnect, serverTimestamp } from "firebase/database";

const db = getDatabase();
const userLastOnlineRef = ref(db, "users/joe/lastOnline");
onDisconnect(userLastOnlineRef).set(serverTimestamp());

גרסת אינטרנט 8

var userLastOnlineRef = firebase.database().ref("users/joe/lastOnline");
userLastOnlineRef.onDisconnect().set(firebase.database.ServerValue.TIMESTAMP);

להטות שעון

בעוד firebase.database.ServerValue.TIMESTAMP הוא הרבה יותר מדויק, ועדיפה על פעולות קריאה / כתיבה ביותר, זה יכול להיות שימושי מדי פעם כדי להעריך את השעון הלקוח הטייה ביחס לשרתים של מסד Firebase זמן אמת. ניתן לצרף התקשרות למיקום /.info/serverTimeOffset להשיג את הערך, באלפיות השנייה, כי Firebase זמן אמת לקוחות מסד להוסיף זמן מקומי דיווח (זמן עידן באלפיות השנייה) כדי להעריך את הזמן בשרת. שים לב שדיוק הקיזוז הזה יכול להיות מושפע מאיחור ברשת, ולכן הוא שימושי בעיקר לגילוי פערים גדולים (> שנייה אחת) בזמן השעון.

גרסת אינטרנט 9

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;
});

גרסת אינטרנט 8

var offsetRef = firebase.database().ref(".info/serverTimeOffset");
offsetRef.on("value", (snap) => {
  var offset = snap.val();
  var estimatedServerTimeMs = new Date().getTime() + offset;
});

אפליקציית נוכחות לדוגמא

על ידי שילוב פעולות ניתוק עם ניטור מצב חיבור וחותמות זמן של שרת, תוכל לבנות מערכת נוכחות של משתמשים. במערכת זו, כל משתמש מאחסן נתונים במיקום מסד נתונים כדי לציין אם לקוח מסד נתונים בזמן אמת מחובר או לא. לקוחות מגדירים את המיקום הזה כנכון כאשר הם נכנסים לרשת וחותמת זמן כשהם מתנתקים. חותמת זמן זו מציינת את הפעם האחרונה בה המשתמש נתון היה מקוון.

שים לב שהאפליקציה שלך צריכה לתור את פעולות הניתוק לפני שמשתמש מסומן באופן מקוון, כדי למנוע תנאי מירוץ במקרה שחיבור הרשת של הלקוח יאבד לפני שניתן יהיה לשלוח את שתי הפקודות לשרת.

להלן מערכת נוכחות פשוטה של ​​משתמשים:

גרסת אינטרנט 9

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());
  }
});

גרסת אינטרנט 8

// 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);
  }
});