我在Firebase中有一个如下所示的架构:
messages/
$groupId/
$messageId/
message: 'Sample Message'
createdBy: 'userID'
createdAt: 1513337977055
然后我在我的代码中连续执行了以下查询:
// 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
在这里被调用两次,第一个类似于once('value')
查询返回的值。
以下是控制台显示的内容:
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添加新条目。只是查询。
编辑:这是一个演示问题的小提琴链接:https://jsfiddle.net/dspLwvc3/2/
答案 0 :(得分:5)
firebase here
你在那里发现了一个非常有趣的边缘案例。您所看到的行为是系统运行的预期。但我认为我们都同意它远非直观。 : - /
这基本上是一种竞争条件,加上Firebase对它将会发生什么,不发射以及发生事件的保证。
基本上会发生什么:
Client Server
| |
(1)| --once('value'----> |
| |
(2)| -on('child_added'-> |
| |
| . |
| . |
| . |
| |
| value |
(3)| <------------------- |
| |
| child |
(4)| <------------------- |
| |
那里有4个关键时刻:
once('value')
附加了/messages/message1
听众。客户端将请求发送到服务器并等待。您为on(-child_added
的最后一个已知密钥附加了/messages
侦听器。客户端将请求发送到服务器并等待。
对第一个请求的响应从服务器返回。在这个阶段有两个听众。 once('value
监听器是清晰的,因此它会触发并被删除。但此时/messages/message1
也是/messages
的最后一个已知密钥,因此客户端也会触发child_added
侦听器。
/messages/message3
的响应从服务器返回。只剩下一个听众,它要求听到最后一条消息,所以它会触发。请注意,如果您还有一个child_removed
的监听器,那么此时它将适用于/messages/message1
。正如我所说,它不是很直观。但从系统的角度来看,这是正确的行为。这意味着您不希望出现此行为,您将需要以不同的方式使用API。使用当前代码的最简单的方法是将child_added
侦听器附加到 once('value'
回调中:
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
侦听器时,/messages/message1
快照已经从客户端的缓存中刷新。
更新(2018-01-07):另一位开发人员遇到此行为,并且很难维护子级的顺序。所以我写了一些关于这种行为(虽然意外)仍然保持孩子的正确顺序的更多信息。有关详情,请参阅我的回答:Firebase caching ruins order of retrieved children