每当我在NodeJS中定义Firebase事务时,我注意到它总是运行三次 - 前两次使用空数据,然后最后第三次使用实际数据。这是正常的吗?
例如这段代码:
firebaseOOO.child('ref').transaction(function(data) {
console.log(data);
return data;
});
输出以下内容:
null
null
i1: { a1: true }
我原以为它只打印最后一项。
要回答评论中的问题,这里的回调是一样的:
firebaseOOO.child('ref').transaction(function(data) {
console.log(data);
return data;
}, function(error, committed, snapshot) {
if (error)
console.log('failed');
else if (!committed)
console.log('aborted');
else
console.log('committed');
console.log('fin');
});
产生以下输出:
null
null
i1: { a1: true }
committed
fin
在发布问题之前,我已经阅读了交易如何运作的详细信息,因此我尝试将applyLocally设置为false,如下所示:
firebaseOOO.child('ref').transaction(function(data) {
console.log('hit');
return data;
}, function(){}, false);
但它仍然会击中3次(只是双重检查),所以我认为这是不同的东西。在交易之前获得“价值”确实“按预期”工作,因为它只会点击一次,而且不管applyLocally设置的是什么,所以我不确定applyLocally会做什么?这就是我在交易前获得价值的意思:
firebaseOOO.child('ref').once('value', function(data) {
console.log('1');
firebaseOOO.child('ref').transaction(function(data) {
console.log('2');
return data;
});
});
输出:
1
2
@Michael:如何利用这种行为?事务主要是让数据使用自身来修改自身 - 原型增量++场景。因此,如果我需要将现有值10添加1,并继续使用11的结果,那么函数命中的前两次我将得到一个我需要处理的错误结果,最后是正确的结果第三次打击11。我怎样才能利用这两个初始1?另一种情况(也许我不应该为此使用事务,但如果它像我预期的那样工作使代码更清晰)是插入一个值,如果它还不存在。如果事务只触发一次,则空值意味着该值不存在,因此您可以,例如,在这种情况下,将计数器初始化为1,否则将值1添加到任何值。使用嘈杂的空值,这是不可能的。
从这一切看来,似乎只是简单地使用“一次”模式而不是?
ONCE TRANSACTION PATTERN:
firebaseOOO.child('ref').once('value', function(data) {
console.log('1');
firebaseOOO.child('ref').transaction(function(data) {
console.log('2');
return data;
});
});
答案 0 :(得分:2)
您在此处看到的行为与Firebase如何触发本地事件,然后最终与Firebase服务器同步有关。在这个具体的例子中,“运行三次”只会在你第一次运行代码时发生 - 之后,状态已经完全同步,从那时起它只会触发一次。此处详细说明了此行为:https://www.firebase.com/docs/transactions.html(请参阅“运行事务时,发生以下情况”部分。)
例如,如果您在同一位置有一个未完成的on(),然后在稍后的某个时间运行相同的事务代码,您将看到它只运行一次。这是因为在事务运行之前一切都是同步的(在理想情况下;禁止任何正常冲突等)。
答案 1 :(得分:0)
transaction()将被多次调用,并且必须能够处理空数据。即使数据库中存在现有数据,也可能在运行事务函数时本地缓存它。
firebaseOOO.child('ref').transaction(function(data) {
if(data!=null){
console.log(data);
return data;
}
else {
return data;
}
}, function(error, committed, snapshot) {
if (error)
console.log('failed');
else if (!committed)
console.log('aborted');
else
console.log('committed');
console.log('fin');
});