Firebase onDisconnect现在不是100%可靠吗?

时间:2013-06-12 15:38:47

标签: firebase

我一直在广泛使用Firebase,但仍然只面临一个真正的问题:根据我的经验,onDisconnect并非100%可靠。

如果您在没有先关闭窗口的情况下关闭计算机,或者终止浏览器,那么有时会让“垃圾收集器”执行onDisconnect,有时则不会。

我的问题如下:我现在暂时不使用/.connected,我基本上使用简单的

userRef.set('status', 1);
userRef.onDisconnect().update({ 'status' : 0 });

这种方法有什么问题吗?我们是否同意更新参数在执行行时而不是在窗口卸载之前传递给服务器?

注意:我碰巧尝试保持多窗口状态,如果另一个窗口关闭,使用以下方法将状态保持为1:

userRef.child('status').on('value', function(snap) {
  if (snap.val() != 1) {
    userRef.set('status', 1);
  }
});

我不知道这是如何相关的,但是......

我的解决方案:事实上,我刚刚错过了您了解onDisconnect只触发一次的部分。要获得持久性onDisconnect,您需要实现基本持久性。

Helpers.onConnected = function(callback) {
    var connectedRef = lm.newFirebase('.info/connected');
    var fn =  connectedRef.on('value', function(snap) {
      if (snap.val() === true) {
          if (callback) callback();
      }
    });
    var returned = {};
    returned.cancel = function() {
        connectedRef.off('value', fn);
    };
    return returned;
};       

简单用例:

        this._onConnected = lm.helpers.onConnected(function() {
            this.firebase.onDisconnect().update({ 'tu': 0 });
        }.bind(this));

然后取消:

        if (this._onConnected) this._onConnected.cancel();
        this.firebase.onDisconnect().cancel();

3 个答案:

答案 0 :(得分:5)

在调用set()操作之前,应始终调用onDisconnect()操作。这样,如果两者之间的连接丢失,你就不会得到僵尸数据了。

另请注意,在网络连接未被彻底清除的情况下,您可能必须等待TCP超时才能检测到用户已离开并触发断开连接清除。将进行清理,但可能需要几分钟。

答案 1 :(得分:0)

经过大量挖掘,我发现this issue确实是我的情况,我认为对于大多数要访问此页面的其他人来说,也是这样。

因此问题是,当1。accessToken入队且 2时,firebase会对其onDisconnect进行两次检查。在应用onDsiconnect。 当标签不可见时,Firebase 不会主动刷新令牌。如果页面在accessToken的有效期内无效,并且在没有关注该选项卡的情况下关闭,则由于onDisconnect过期,firebase将不允许accessToken

解决方案:

  1. 您可以通过设置某种方式来获得新的accessToken 这样的间隔:

    let intervalId;
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible') {
        if (intervalId) {
          window.clearTimeout(intervalId);
          intervalId = undefined;
        }
      } else {
        firebaseApp.auth().currentUser.getIdToken(true);
    
        intervalId = setInterval(() => {
          firebaseApp.auth().currentUser.getIdToken(true);
        }, intervalDuration);
      }
    });
    
  2. 或者,只要选项卡可见性从“可见”更改为firebase.database().goOffline(),就可以手动断开数据库连接。

答案 2 :(得分:0)

扩展评论:

This is why we provide the /.info/connected endpoint. 
We recommend re-establishing the disconnect handler every time the connection comes back online

我按照上面的说明进行了修复:

    const userRef = Firebase.database().ref('/users/<user-id>')

    Firebase.database()
      .ref('.info/connected')
      .on('value', async snap => {
        if (snap.val() === true) {
          userRef.onDisconnect().remove())
          await userRef.update({ status : 'online' })
        } else {
          await this.userRef.remove()
        }
      })

作为参考,我之前的代码是:

    const userRef = Firebase.database().ref('/users/<user-id>')
    userRef.onDisconnect().remove())
    await userRef.update({ status : 'online' })

问题是,当您离线并多次重新联机时,onDisconnect可能无法工作