Check out what’s new from Firebase at Google I/O 2022. Learn more

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

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

ניהול נוכחות

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

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

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

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

Web version 8

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

איך onDisconnect עובד

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

האפליקציה שלך יכולה להשתמש בהתקשרות חזרה בפעולת הכתיבה כדי לוודא שה- onDisconnect צורף כהלכה:

Web version 9

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

Web version 8

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

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

Web version 9

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

Web version 8

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

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

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

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

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

טיפול ב-Latency

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

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

Web version 9

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

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

Web version 8

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

להטות שעון

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

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

Web version 8

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

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

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

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

הנה מערכת נוכחות משתמש פשוטה:

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

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