แอปพลิเคชัน Firebase ทำงานได้แม้ว่าแอปของคุณจะขาดการเชื่อมต่อเครือข่ายชั่วคราว เรามีเครื่องมือหลายอย่างสำหรับการตรวจสอบการแสดงตนและการซิงโครไนซ์สถานะโลคัลกับสถานะเซิร์ฟเวอร์ ซึ่งแนะนำไว้ในเอกสารนี้
การจัดการการแสดงตน
ในแอปพลิเคชันเรียลไทม์ การตรวจจับเมื่อไคลเอนต์เชื่อมต่อและยกเลิกการเชื่อมต่อมักมีประโยชน์ ตัวอย่างเช่น คุณอาจต้องการทำเครื่องหมายผู้ใช้ว่า 'ออฟไลน์' เมื่อไคลเอนต์ของพวกเขายกเลิกการเชื่อมต่อ
ไคลเอนต์ฐานข้อมูล Firebase จัดเตรียมพื้นฐานง่ายๆ ที่คุณสามารถใช้เพื่อเขียนไปยังฐานข้อมูลเมื่อไคลเอ็นต์ยกเลิกการเชื่อมต่อจากเซิร์ฟเวอร์ฐานข้อมูล Firebase การอัปเดตเหล่านี้จะเกิดขึ้นไม่ว่าไคลเอ็นต์จะตัดการเชื่อมต่ออย่างสมบูรณ์หรือไม่ ดังนั้นคุณจึงสามารถวางใจได้ในการล้างข้อมูลแม้ว่าการเชื่อมต่อจะหลุดหรือไคลเอ็นต์ขัดข้อง การดำเนินการเขียนทั้งหมด รวมถึงการตั้งค่า การอัพเดต และการลบ สามารถดำเนินการได้เมื่อตัดการเชื่อมต่อ
นี่คือตัวอย่างง่ายๆ ของการเขียนข้อมูลเมื่อตัดการเชื่อมต่อโดยใช้ onDisconnect
ดั้งเดิม:
Web modular API
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 namespaced API
var presenceRef = firebase.database().ref("disconnectmessage"); // Write a string when this client loses connection presenceRef.onDisconnect().set("I disconnected!");
วิธีการตัดการเชื่อมต่อทำงานอย่างไร
เมื่อคุณสร้างการดำเนินการ onDisconnect()
การดำเนินการนั้นจะอยู่บนเซิร์ฟเวอร์ Firebase Realtime Database เซิร์ฟเวอร์จะตรวจสอบความปลอดภัยเพื่อให้แน่ใจว่าผู้ใช้สามารถดำเนินการเขียนตามที่ร้องขอ และแจ้งแอปของคุณหากแอปไม่ถูกต้อง จากนั้นเซิร์ฟเวอร์จะตรวจสอบการเชื่อมต่อ หากการเชื่อมต่อหมดเวลาหรือถูกปิดโดยไคลเอ็นต์ฐานข้อมูลเรียลไทม์ เซิร์ฟเวอร์จะตรวจสอบความปลอดภัยเป็นครั้งที่สอง (เพื่อให้แน่ใจว่าการดำเนินการยังคงถูกต้อง) จากนั้นจึงเรียกใช้เหตุการณ์
แอปของคุณสามารถใช้การเรียกกลับในการเขียนเพื่อให้แน่ใจว่า onDisconnect
ถูกแนบอย่างถูกต้อง:
Web modular API
onDisconnect(presenceRef).remove().catch((err) => { if (err) { console.error("could not establish onDisconnect event", err); } });
Web namespaced API
presenceRef.onDisconnect().remove((err) => { if (err) { console.error("could not establish onDisconnect event", err); } });
เหตุการณ์ onDisconnect
สามารถยกเลิกได้โดยการโทร .cancel()
:
Web modular API
const onDisconnectRef = onDisconnect(presenceRef); onDisconnectRef.set("I disconnected"); // some time later when we change our minds onDisconnectRef.cancel();
Web namespaced API
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 modular API
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 namespaced API
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
เป็นเท็จ สิ่งนี้ไม่รับประกันว่าไคลเอนต์ที่แยกจากกันจะอ่านเป็นเท็จ
การจัดการเวลาแฝง
การประทับเวลาของเซิร์ฟเวอร์
เซิร์ฟเวอร์ Firebase Realtime Database มีกลไกในการแทรกการประทับเวลาที่สร้างขึ้นบนเซิร์ฟเวอร์เป็นข้อมูล คุณลักษณะนี้เมื่อรวมกับ onDisconnect
เป็นวิธีง่ายๆ ในการจดบันทึกเวลาที่ไคลเอ็นต์ Realtime Database ตัดการเชื่อมต่อ:
Web modular API
import { getDatabase, ref, onDisconnect, serverTimestamp } from "firebase/database"; const db = getDatabase(); const userLastOnlineRef = ref(db, "users/joe/lastOnline"); onDisconnect(userLastOnlineRef).set(serverTimestamp());
Web namespaced API
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 modular API
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 namespaced API
var offsetRef = firebase.database().ref(".info/serverTimeOffset"); offsetRef.on("value", (snap) => { var offset = snap.val(); var estimatedServerTimeMs = new Date().getTime() + offset; });
ตัวอย่างการแสดงตน App
ด้วยการรวมการดำเนินการยกเลิกการเชื่อมต่อเข้ากับการตรวจสอบสถานะการเชื่อมต่อและการประทับเวลาของเซิร์ฟเวอร์ คุณสามารถสร้างระบบการแสดงตนของผู้ใช้ได้ ในระบบนี้ ผู้ใช้แต่ละคนเก็บข้อมูลไว้ที่ตำแหน่งฐานข้อมูลเพื่อระบุว่าไคลเอ็นต์ Realtime Database ออนไลน์อยู่หรือไม่ ลูกค้าตั้งค่าตำแหน่งนี้เป็นจริงเมื่อออนไลน์และประทับเวลาเมื่อยกเลิกการเชื่อมต่อ การประทับเวลานี้ระบุเวลาล่าสุดที่ผู้ใช้ออนไลน์ออนไลน์
โปรดทราบว่าแอปของคุณควรจัดคิวการดำเนินการตัดการเชื่อมต่อก่อนที่ผู้ใช้จะถูกทำเครื่องหมายว่าออนไลน์ เพื่อหลีกเลี่ยงสภาวะการแย่งชิงในกรณีที่การเชื่อมต่อเครือข่ายของไคลเอ็นต์ขาดหายไปก่อนที่จะสามารถส่งคำสั่งทั้งสองไปยังเซิร์ฟเวอร์ได้
นี่คือระบบการแสดงตนของผู้ใช้อย่างง่าย:
Web modular API
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 namespaced API
// 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); } });