فعال کردن قابلیت های آفلاین در جاوا اسکریپت

برنامه های Firebase حتی اگر برنامه شما به طور موقت اتصال شبکه خود را قطع کند، کار می کنند. ما چندین ابزار برای نظارت بر حضور و همگام سازی حالت محلی با وضعیت سرور ارائه می دهیم که در این سند معرفی شده اند.

مدیریت حضور

در برنامه‌های بلادرنگ، تشخیص زمان اتصال و قطع ارتباط کلاینت‌ها اغلب مفید است. برای مثال، ممکن است بخواهید زمانی که مشتری قطع می شود، کاربر را به عنوان "آفلاین" علامت گذاری کنید.

کلاینت های پایگاه داده Firebase ابتدایی های ساده ای را ارائه می دهند که می توانید از آنها برای نوشتن در پایگاه داده زمانی که کلاینت از سرورهای پایگاه داده Firebase جدا می شود استفاده کنید. این به‌روزرسانی‌ها چه اتصال کلاینت به‌طور تمیز قطع شود یا خیر، رخ می‌دهند، بنابراین می‌توانید برای پاک‌سازی داده‌ها به آنها اعتماد کنید، حتی اگر اتصال قطع شود یا کلاینت خراب شود. تمام عملیات نوشتن، از جمله تنظیم، به روز رسانی، و حذف، می تواند در صورت قطع اتصال انجام شود.

در اینجا یک مثال ساده از نوشتن داده در هنگام قطع اتصال با استفاده از onDisconnect ابتدایی آورده شده است:

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

چگونه onDisconnect کار می کند

هنگامی که یک عملیات onDisconnect() ایجاد می کنید، این عملیات در سرور Firebase Realtime Database زندگی می کند. سرور امنیت را بررسی می کند تا مطمئن شود کاربر می تواند رویداد نوشتن درخواستی را انجام دهد و در صورت نامعتبر بودن برنامه شما را به اطلاع می رساند. سپس سرور اتصال را کنترل می کند. اگر در هر نقطه ای زمان اتصال تمام شود، یا به طور فعال توسط سرویس گیرنده Realtime Database بسته شود، سرور برای بار دوم امنیت را بررسی می کند (برای اطمینان از اینکه عملیات همچنان معتبر است) و سپس رویداد را فراخوانی می کند.

برنامه شما می‌تواند از پاسخ به تماس در عملیات نوشتن استفاده کند تا مطمئن شود onDisconnect به درستی متصل شده است:

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

یک رویداد onDisconnect را نیز می توان با فراخوانی .cancel() لغو کرد:

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

تشخیص وضعیت اتصال

برای بسیاری از ویژگی های مربوط به حضور، برای برنامه شما مفید است که بداند چه زمانی آنلاین یا آفلاین است. Firebase Realtime Database یک مکان ویژه در /.info/connected ارائه می دهد که هر بار که وضعیت اتصال سرویس گیرنده Firebase Realtime Database تغییر می کند، به روز می شود. در اینجا یک مثال است:

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 یک مقدار بولی است که بین کلاینت‌های Realtime Database همگام‌سازی نمی‌شود، زیرا مقدار به وضعیت مشتری بستگی دارد. به عبارت دیگر، اگر یک کلاینت /.info/connected را به عنوان false بخواند، این تضمینی نیست که یک کلاینت جداگانه نیز false را بخواند.

رسیدگی به تاخیر

مهر زمانی سرور

سرورهای Firebase Realtime Database مکانیزمی را برای درج مُهرهای زمانی تولید شده روی سرور به عنوان داده فراهم می کنند. این ویژگی، همراه با onDisconnect ، راه آسانی را برای یادداشت‌برداری مطمئن از زمان قطع ارتباط مشتری Realtime Database ارائه می‌کند:

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

کج بودن ساعت

در حالی که firebase.database.ServerValue.TIMESTAMP بسیار دقیق تر است و برای اکثر عملیات خواندن/نوشتن ارجح است، گاهی اوقات تخمین انحراف ساعت مشتری با توجه به سرورهای Firebase Realtime Database می تواند مفید باشد. می‌توانید یک تماس برگشتی را به مکان /.info/serverTimeOffset متصل کنید تا مقداری را که مشتریان Firebase Realtime Database بر حسب میلی‌ثانیه به زمان گزارش شده محلی (زمان دوره به میلی‌ثانیه) برای تخمین زمان سرور اضافه می‌کنند، به دست آورید. توجه داشته باشید که دقت این افست می‌تواند تحت‌تاثیر تأخیر شبکه قرار گیرد، و بنابراین اساساً برای کشف اختلافات بزرگ (> 1 ثانیه) در زمان ساعت مفید است.

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

نمونه برنامه حضور

با ترکیب عملیات قطع اتصال با نظارت بر وضعیت اتصال و مهرهای زمانی سرور، می توانید یک سیستم حضور کاربر بسازید. در این سیستم، هر کاربر داده‌ها را در یک مکان پایگاه داده ذخیره می‌کند تا مشخص کند آیا یک سرویس گیرنده Realtime Database آنلاین است یا نه. مشتریان زمانی که آنلاین می‌شوند، این مکان را روی true و هنگام قطع ارتباط یک مهر زمانی تنظیم می‌کنند. این مهر زمان آخرین باری را که کاربر مورد نظر آنلاین بوده است نشان می دهد.

توجه داشته باشید که برنامه شما باید قبل از اینکه کاربر به صورت آنلاین علامت گذاری شود، عملیات قطع اتصال را در صف قرار دهد تا در صورت قطع شدن اتصال شبکه مشتری قبل از ارسال هر دو دستور به سرور، از هرگونه شرایط مسابقه جلوگیری شود.

در اینجا یک سیستم حضور کاربر ساده وجود دارد:

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