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

Firebase onDisconnect现在不是100%可靠吗?,firebase,Firebase,我一直在广泛使用Firebase,但仍然面临一个真正的问题:根据我的经验,onDisconnect不是100%可靠的 如果您没有先关闭窗口就关闭了计算机,或者关闭了浏览器,那么“垃圾收集器”有时会执行onDisconnect,有时则不会 我的问题是:我只是不使用/。现在,我基本上使用一个简单的 userRef.set('status', 1); userRef.onDisconnect().update({ 'status' : 0 }); 这种方法有什么问题吗?我们是否同意在执行行时而不是在

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

如果您没有先关闭窗口就关闭了计算机,或者关闭了浏览器,那么“垃圾收集器”有时会执行onDisconnect,有时则不会

我的问题是:我只是不使用/。现在,我基本上使用一个简单的

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

在调用set()操作之前,应该始终调用onDisconnect()操作。这样,如果两者之间的连接丢失,则不会出现僵尸数据


还要注意的是,如果网络连接没有完全终止,您可能需要等待TCP超时,然后才能检测到用户已离开并触发断开连接清理。清理工作将会进行,但可能需要几分钟。

在进行了大量的挖掘之后,我发现在我的案例中确实发生了这种情况,我想对于大多数来到本页寻求解决方案的其他人来说也是如此

所以问题是firebase在1时检查它的
accessToken
两次。
onDisconnect
已排队且2。当应用
onDsiconnect
。 当选项卡不可见时,Firebase不会主动刷新令牌。如果页面在
accessToken
过期之后处于非活动状态,并且在未关注该选项卡的情况下关闭,firebase将不允许
onDisconnect
,因为
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);
      }
    });
    
  • 或者,每当选项卡可见性从“可见”更改时,您可以手动断开数据库的连接


  • 在评论的基础上扩展:

    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/'))
    Firebase.database()
    .ref(“.info/connected”)
    .on('value',异步快照=>{
    if(snap.val()==真){
    等待userRef.onDisconnect().remove();
    等待userRef.update({status:'online'})
    }否则{
    等待此消息。userRef.remove()
    }
    });
    
    作为参考,我以前的代码是:

    const userRef=Firebase.database().ref('/users/'))
    userRef.onDisconnect().remove();
    等待userRef.update({status:'online'})
    

    这样做的问题是,当您脱机并多次联机时,onDisconnect可能无法工作

    问题是,我仍然拥有大约20%的onDisconnect,不幸的是,这些onDisconnect从未被呼叫过,导致人们似乎永远保持连接。当调用onDisconnect时,100%确定至少有几分钟的连接仍然存在,您是否有办法了解正在发生的情况?在客户端断开连接后,您要等待多长时间?在某些极端情况下可能需要5分钟。另外-您是否有阻止断开连接操作的安全规则?测试用例也会有所帮助。你有超简单测试用例的链接吗?Andrew,我终于找到了问题的根源。我的错误:我从未真正意识到onDisconnect只是在您第一次断开连接时才被调用。这解释了我们所有的bug。。。我肯定会在你的网站上用红色+粗体。我能推荐一个简单的插件吗?我不知道其他项目的情况,但在我们的情况下,我们总是希望在将来的onDisconnect上再次调用onDisconnect(想象一下,一个用户有一个坏连接,它一直在断开/重新连接)。我的建议是,如果我们希望在将来的每次断开连接时都调用onDisconnect,我们能否将其作为一个论点传递给onDisconnect?看起来是这样的:ref.onDisconnect(true).update(down);这就是我们提供/.info/connected端点的原因。我们建议每次连接重新联机时重新建立断开连接处理程序。请参见此处的最后一个代码段: