การเปิดใช้งานความสามารถแบบออฟไลน์ใน JavaScript

แอปพลิเคชัน 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() อยู่ที่เซิร์ฟเวอร์ Firebase Realtime Database เซิร์ฟเวอร์จะตรวจสอบความปลอดภัยเพื่อ ตรวจสอบว่าผู้ใช้สามารถทำกิจกรรมการเขียนตามที่ขอได้ แล้วแจ้งข้อมูล แอปของคุณหากไม่ถูกต้อง จากนั้นเซิร์ฟเวอร์ ติดตามดูการเชื่อมต่อ หากการเชื่อมต่อหมดเวลา หรือ มีการปิดอย่างต่อเนื่องโดยไคลเอ็นต์ Realtime Database เซิร์ฟเวอร์จะตรวจสอบความปลอดภัย ครั้งที่ 2 (เพื่อให้มั่นใจว่าการดำเนินการยังคงถูกต้อง) แล้วจึงเรียกใช้ กิจกรรมนั้น

แอปของคุณสามารถใช้ Callback ในการดำเนินการเขียน เพื่อตรวจสอบว่าการแนบ 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 ด้วย

การจัดการเวลาในการตอบสนอง

การประทับเวลาของเซิร์ฟเวอร์

เซิร์ฟเวอร์ 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 คุณ สามารถแนบ Callback ไปยังตำแหน่ง /.info/serverTimeOffset เพื่อรับค่าเป็นมิลลิวินาทีที่ไคลเอ็นต์ Firebase Realtime Database เพิ่มลงในเวลาที่รายงานในท้องถิ่น (เวลา Epoch ในหน่วยมิลลิวินาที) เพื่อประมาณการ เวลาของเซิร์ฟเวอร์ โปรดทราบว่าความแม่นยำของออฟเซ็ตนี้อาจได้รับผลกระทบจาก เวลาในการตอบสนองของเครือข่าย และ มีประโยชน์สำหรับการค้นพบ เวลาของนาฬิกามีความคลาดเคลื่อนมาก (> 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 รายออนไลน์ ลูกค้าตั้งค่าตำแหน่งนี้เป็น "จริง" เมื่อ ผู้ใช้กลับมาออนไลน์และมีการประทับเวลาเมื่อยกเลิกการเชื่อมต่อ การประทับเวลานี้ ระบุเวลาล่าสุดที่ผู้ใช้ที่ระบุออนไลน์

โปรดทราบว่าแอปของคุณควรจัดคิวการดำเนินการยกเลิกการเชื่อมต่อก่อนที่ผู้ใช้จะ ที่ระบุทางออนไลน์ เพื่อหลีกเลี่ยงเงื่อนไขการแข่งขันในกรณีที่ลูกค้า การเชื่อมต่อเครือข่ายขาดหายก่อนที่จะส่งทั้งสองคำสั่งไปยังเซิร์ฟเวอร์

ต่อไปนี้เป็นระบบการตรวจหาผู้ใช้แบบง่าย:

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