jay*_*aye 4 javascript firebase firebase-realtime-database
我在Firebase中有一个架构,如下所示:
messages/
$groupId/
$messageId/
message: 'Sample Message'
createdBy: 'userID'
createdAt: 1513337977055
Run Code Online (Sandbox Code Playgroud)
然后,我在代码中连续执行以下查询:
// 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()))
Run Code Online (Sandbox Code Playgroud)
我想知道为什么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' }
Run Code Online (Sandbox Code Playgroud)
请注意,我不会在此处向Firebase添加新条目。只是查询。
编辑:这是一个演示问题的小提琴链接:https : //jsfiddle.net/dspLwvc3/2/
在这里火力
您在那里发现了一个非常有趣的边缘案例。从系统的运行情况来看,您所看到的行为是预期的。但是我认为我们都可以同意这远非直觉。:-/
本质上讲,这是一种竞赛条件,结合了Firebase对它将触发和不触发以及何时触发事件的保证。
本质上会发生以下情况:
Client Server
| |
(1)| --once('value'----> |
| |
(2)| -on('child_added'-> |
| |
| . |
| . |
| . |
| |
| value |
(3)| <------------------- |
| |
| child |
(4)| <------------------- |
| |
Run Code Online (Sandbox Code Playgroud)
这里有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()))
})
Run Code Online (Sandbox Code Playgroud)
之所以child_added
可行,是因为在连接侦听器时,/messages/message1
快照已经从客户端的缓存中清除了。
更新(2018-01-07):另一个开发人员遇到此行为,并且很难维护孩子的顺序。因此,我写了一些更多的内容,这种行为(尽管出乎意料)如何仍然保持孩子的正确顺序。有关更多信息,请在此处查看我的答案:Firebase缓存破坏了被回收儿童的顺序