Firebase查询:为什么在以下代码中的值查询之前调用了child_added? [英] Firebase query: Why is child_added called before the value query in the following code?
问题描述
我在Firebase中有一个如下所示的架构:
I have a schema in Firebase that looks like this:
messages/
$groupId/
$messageId/
message: 'Sample Message'
createdBy: 'userID'
createdAt: 1513337977055
然后我在我的代码中连续执行以下查询:
Then I have the following queries executed consecutively in my code:
// Get a specific message
ref.child('messages/$groupId/$messageId')
.once('value')
.then(snap => console.log('value', snap.val()))
// Start new message listener
ref.child('messages/$groupId')
.orderByKey()
.limitToLast(1)
.on('child_added', snap => console.log('child_added', snap.val()))
我想知道为什么 child_added
在这里被调用两次,第一个类似于<$ c $返回的值c>一次('值')查询。
I'm wondering why child_added
gets called twice here, the first one being similar to the value returned by the once('value')
query.
以下是控制台显示的内容:
Here's what the console displays:
child_added { message: 'Hello', createdAt: 1513337977055, createdBy: 'userId' }
value { message: 'Hello', createdAt: 1513337977055, createdBy: 'userId' }
child_added { message: 'Another message', createdAt: 1513337977066, createdBy: 'userId2' }
请注意,我不会在此处向Firebase添加新条目。只是查询。
Note that I'm not adding new entries to Firebase here. Just querying.
编辑:这是一个演示问题的小提琴链接: https://jsfiddle.net/dspLwvc3/2/
Here is a fiddle link demonstrating the issue: https://jsfiddle.net/dspLwvc3/2/
推荐答案
firebase here
你在那里发现了一个非常有趣的边缘案例。您所看到的行为是系统运行的预期。但我认为我们都同意它远非直观。 : - /
You've uncovered a quite interesting edge case there. The behavior you're seeing is expected from how the system operates. But I think we can all agree that it's far from intuitive. :-/
这实际上是一种竞争条件,加上Firebase对它将会发生什么,不会发生什么以及何时发生事件的保证。
It's essentially a race condition, combined with Firebase's guarantees about what it will and won't fire and when it fires events.
基本上会发生这样的事情:
Essentially what happens is this:
Client Server
| |
(1)| --once('value'----> |
| |
(2)| -on('child_added'-> |
| |
| . |
| . |
| . |
| |
| value |
(3)| <------------------- |
| |
| child |
(4)| <------------------- |
| |
那里有4个关键时刻:
- 您为
/ messages / message1附加
。客户端将请求发送到服务器并等待。一次('值')
听众 -
您附加
(-child_added
最后一次知道密钥/ messages
的监听器。客户端将请求发送到服务器并等待。
- You attach a
once('value')
listener for/messages/message1
. The client sends the request to the server and waits. You attach a
on(-child_added
listener for the last-known key of/messages
. The client sends the request to the server and waits.
对第一个请求的回复是ba来自服务器的ck。在这个阶段有两个听众。 一次('value
监听器是清除的,因此它会触发并被删除。但此时 / messages / message1
也是 / messages
的最后一个已知密钥,因此客户端也会触发 child_added
监听器。
The response to the first request comes back from the server. At this stage there are two listeners. The once('value
listener is clear, so it fires and is removed. But at this point /messages/message1
is also the last-known key of /messages
, so the client fires that child_added
listener too.
正如我所说,这不是很直观。但从系统的角度来看,这是正确的行为这意味着你不想要这种行为,你需要以不同的方式使用API。最简单的一个用你当前的代码将移动附加 child_added
听众进入 一次('值'
回调:
As I said, it's not very intuitive. But from the system's perspective it is the correct behavior. That means that you don't want this behavior, you will need to use the API in a different way. The simplest one with your current code would be to move attaching the child_added
listener into the once('value'
callback:
ref.child('messages/$groupId/$messageId')
.once('value')
.then(snap => {
console.log('value', snap.val()))
// Start new message listener
ref.child('messages/$groupId')
.orderByKey()
.limitToLast(1)
.on('child_added', snap => console.log('child_added', snap.val()))
})
这是因为,当 child_added $ c时附加了$ c>侦听器,
/ messages / message1
快照已从客户端缓存中刷新。
This works because, by the time the child_added
listener is attached, the /messages/message1
snapshot has already been flushed from the client's cache.
更新(2018-01-07):另一位开发人员遇到此行为并且很难维护子项的顺序。所以我写了一些关于这种行为(虽然意外)仍然保持孩子的正确顺序的更多信息。有关详细信息,请参阅我的答案: Firebase缓存废墟检索顺序孩子
Update (2018-01-07): another developer encountered this behavior and had a hard time maintaining the order of children. So I wrote up a bit more how this behavior (while unexpected) still maintains the correct order of the children. For more, see my answer here: Firebase caching ruins order of retrieved children
这篇关于Firebase查询:为什么在以下代码中的值查询之前调用了child_added?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!