我在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添加新条目。只是查询。
编辑:这是一个演示该问题的 fiddle 链接:https://jsfiddle.net/dspLwvc3/2/
最佳答案
在这里火力
您在那里发现了一个非常有趣的边缘案例。从系统的运行情况来看,您所看到的行为是预期的。但是我认为我们都可以同意这远非直觉。 :-/
本质上讲,这是一种竞赛条件,结合了Firebase对它将触发和不触发以及何时触发事件的保证。
本质上会发生以下情况:
Client Server
| |
(1)| --once('value'----> |
| |
(2)| -on('child_added'-> |
| |
| . |
| . |
| . |
| |
| value |
(3)| <------------------- |
| |
| child |
(4)| <------------------- |
| |
这里有4个关键时刻:
once('value')
附加了/messages/message1
监听器。客户端将请求发送到服务器并等待。 on(-child_added
的最后一个已知 key 附加了/messages
监听器。客户端将请求发送到服务器并等待。 once('value
监听器是清除的,因此它将触发并被删除。但是在这一点上,/messages/message1
也是/messages
的最后一个已知键,因此客户端也将触发该child_added
监听器。 /messages/message3
的响应从服务器返回。仅剩一个听众,它要求听到最后一条消息,因此它将触发。请注意,如果您还具有child_removed
的监听器,则此时将是/messages/message1
的监听器。 如我所说,这不是很直观。但是从系统的 Angular 来看,这是正确的行为。这意味着您不希望出现这种情况,您将需要以其他方式使用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):另一个开发人员遇到此行为,并且很难维护 child 的顺序。因此,我写了一些更多的内容,说明这种行为(尽管出乎意料)仍然如何保持 child 的正确顺序。有关更多信息,请在此处查看我的答案:Firebase caching ruins order of retrieved children
关于javascript - Firebase查询: Why is child_added called before the value query in the following code?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47921039/