【问题标题】:Unexpected Firebase Firestore collection subscription behaviour意外的 Firebase Firestore 集合订阅行为
【发布时间】:2018-04-03 12:25:36
【问题描述】:

我在订阅集合的 valueChanges 时遇到了一些有趣的行为。

在创建文档后立即调用集合的订阅,但是我只收到一个大小为 1 的数组,而不是许多文档的数组 - 单个新创建的文档。

在阅读完这个(Firestore Docs | Get Realtime Updates)之后,我还是有点困惑。

应用中的本地写入将立即调用快照侦听器。这是因为一个称为“延迟补偿”的重要功能。当您执行写入时,您的侦听器将在数据发送到后端之前收到新数据的通知。

这是否解释了我所看到的行为?


这是一个 stackblitz 演示问题。只需取消注释掉 ngOnInit() 中的注释行并重新加载以查看我认为的预期行为。


我可以通过让一个空订阅在别处监听这个集合,或者直接在之前复制 take(1) 订阅代码来解决这个问题

【问题讨论】:

    标签: javascript angular rxjs rxjs5


    【解决方案1】:

    这是一个很好的收获。很确定你是对的 - valueChanges() 如文档所述:

    您收藏的当前状态。返回一个 Observable 的数据为 JSON 对象的同步数组。

    当你发现自己时:

    应用中的本地写入将立即调用快照侦听器。

    这就是发生的事情:

    您的 addPizza() 是一个 async 函数。它向 backed 发送请求以添加新的比萨饼。但它不会等待任何东西并跳转到您的第二个功能 - this.getPizzasAsyncAwait()。而且因为本地写入会立即调用侦听器,所以您的 Observable 会发出该值并广播它。而且由于您还使用 Rxjs 的 take(1) - 之后它会取消订阅。这也解释了为什么take(2) 会带来所有其他记录。您可以将 getPizzasNormal() 方法移至 OnInit(),您将收到整个集合。

    【讨论】:

    • 是的,不幸的是,情况似乎如此。在过去的几天里,我一直在与这种确切的行为作斗争,因为我正试图减少我正在进行的订阅和 firebase 调用的数量。但是似乎有必要在您的ngOnInits中保持正常订阅(使用limit(1)来减少firebase读取)。感谢@J.D. 的帮助
    • 我认为take(2) 在这种情况下 - 当您以您添加的相同类型订阅时,被认为是一种不错的方式。由于@ibenjelloun 似乎精通该主题,但使用 Promise 的回调可能会产生副作用 - 如果它没有解决,您将不会订阅。 catch()that 当然可以,但是和take(2)比起来,就显得有些沉重了。
    【解决方案2】:

    firebase js sdk 乐观地处理添加,在获取集合值之前,集合尚未定义。添加一个值后,集合包含 1 个值,然后由服务器端值更新。

    如果您想避免在仅通过本地更改设置集合值时获得此中间状态,您可以在开始更改之前订阅,以便在订阅之前完成:

    this.piazzaRef.add({
       name: name,
       addedAt: new Date().toISOString()
    }).then(() => {
       this.getPizzasAsyncAwait();
       this.getPizzasNormal();
    });
    

    I updated your example here

    【讨论】:

      最近更新 更多