Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Habilitación de capacidades sin conexión en JavaScript

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

Las aplicaciones de Firebase funcionan incluso si su aplicación pierde su conexión de red temporalmente. Proporcionamos varias herramientas para monitorear la presencia y sincronizar el estado local con el estado del servidor, que se presentan en este documento.

Gestión de presencia

En las aplicaciones en tiempo real, suele ser útil detectar cuándo se conectan y desconectan los clientes. Por ejemplo, puede marcar a un usuario como 'fuera de línea' cuando su cliente se desconecta.

Los clientes de Firebase Database proporcionan primitivas simples que puede usar para escribir en la base de datos cuando un cliente se desconecta de los servidores de Firebase Database. Estas actualizaciones ocurren ya sea que el cliente se desconecte limpiamente o no, por lo que puede confiar en ellas para limpiar los datos incluso si se interrumpe una conexión o si un cliente falla. Todas las operaciones de escritura, incluidas la configuración, la actualización y la eliminación, se pueden realizar tras una desconexión.

Aquí hay un ejemplo simple de escribir datos al desconectarse usando la primitiva 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!");

Cómo funciona onDisconnect

Cuando establece una operación onDisconnect() , la operación vive en el servidor de Firebase Realtime Database. El servidor verifica la seguridad para asegurarse de que el usuario pueda realizar el evento de escritura solicitado e informa a su aplicación si no es válida. A continuación, el servidor supervisa la conexión. Si en algún momento se agota el tiempo de espera de la conexión o el cliente de Realtime Database la cierra activamente, el servidor comprueba la seguridad por segunda vez (para asegurarse de que la operación sigue siendo válida) y luego invoca el evento.

Su aplicación puede usar la devolución de llamada en la operación de escritura para asegurarse de que onDisconnect se adjuntó correctamente:

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

Un evento onDisconnect también se puede cancelar llamando a .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();

Detección del estado de la conexión

Para muchas funciones relacionadas con la presencia, es útil que su aplicación sepa cuándo está en línea o fuera de línea. Firebase Realtime Database proporciona una ubicación especial en /.info/connected que se actualiza cada vez que cambia el estado de conexión del cliente de Firebase Realtime Database. Aquí hay un ejemplo:

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 es un valor booleano que no está sincronizado entre clientes de Realtime Database porque el valor depende del estado del cliente. En otras palabras, si un cliente lee /.info/connected como falso, esto no garantiza que otro cliente también lea falso.

Latencia de manejo

Marcas de tiempo del servidor

Los servidores de Firebase Realtime Database proporcionan un mecanismo para insertar marcas de tiempo generadas en el servidor como datos. Esta función, combinada con onDisconnect , proporciona una manera fácil de tomar nota de manera confiable del momento en que se desconectó un cliente de 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);

Desviación del reloj

Si bien firebase.database.ServerValue.TIMESTAMP es mucho más preciso y preferible para la mayoría de las operaciones de lectura/escritura, ocasionalmente puede ser útil para estimar el sesgo del reloj del cliente con respecto a los servidores de Firebase Realtime Database. Puede adjuntar una devolución de llamada a la ubicación /.info/serverTimeOffset para obtener el valor, en milisegundos, que los clientes de Firebase Realtime Database agregan a la hora local informada (tiempo de época en milisegundos) para estimar la hora del servidor. Tenga en cuenta que la precisión de este desplazamiento puede verse afectada por la latencia de la red y, por lo tanto, es útil principalmente para descubrir grandes discrepancias (> 1 segundo) en la hora del reloj.

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

Ejemplo de aplicación de presencia

Al combinar las operaciones de desconexión con la supervisión del estado de la conexión y las marcas de tiempo del servidor, puede crear un sistema de presencia del usuario. En este sistema, cada usuario almacena datos en una ubicación de base de datos para indicar si un cliente de Realtime Database está en línea o no. Los clientes configuran esta ubicación como verdadera cuando se conectan y una marca de tiempo cuando se desconectan. Esta marca de tiempo indica la última vez que el usuario dado estuvo en línea.

Tenga en cuenta que su aplicación debe poner en cola las operaciones de desconexión antes de que un usuario se marque en línea, para evitar cualquier condición de carrera en caso de que se pierda la conexión de red del cliente antes de que ambos comandos puedan enviarse al servidor.

Aquí hay un sistema de presencia de usuario simple:

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