意外的 Firebase Firestore 集合订阅行为

Unexpected Firebase Firestore collection subscription behaviour

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

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

看完这篇(Firestore Docs | Get Realtime Updates)我还是有点迷糊。

Local writes in your app will invoke snapshot listeners immediately. This is because of an important feature called "latency compensation." When you perform a write, your listeners will be notified with the new data before the data is sent to the backend.

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


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


我可以通过在其他地方使用空订阅收听此集合,或者直接在

之前复制 take(1) 订阅代码来解决这个问题

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

The current state of your collection. Returns an Observable of data as a synchronized array of JSON objects.

当你发现自己时:

Local writes in your app will invoke snapshot listeners immediately.

事情是这样的:

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

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

如果您希望避免在仅根据本地更改设置集合值时获得此中间状态,您可以在开始之前订阅要在订阅之前完成的更改:

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

I updated your example here