5

每当我在 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 的结果,则函数命中的前两次我将得到需要处理的错误结果 1,最后是正确的结果第三次命中11。我怎样才能利用这两个最初的 1?另一种情况(也许我不应该为此使用事务,但如果它像我预期的那样工作,它会使代码更清晰)是插入一个值(如果它尚不存在)。如果事务只命中一次,则 null 值将意味着该值不存在,因此您可以在这种情况下将计数器初始化为 1,否则将 1 添加到任何值。随着嘈杂的零点,

似乎从这一切中得到的收获是更频繁地使用“一次”模式?

一次交易模式:

firebaseOOO.child('ref').once('value', function(data) {
    console.log('1');
    firebaseOOO.child('ref').transaction(function(data) {
        console.log('2');
        return data;
    });
});
4

2 回答 2

2

您在此处看到的行为与 Firebase 如何触发本地事件并最终与 Firebase 服务器同步有关。在这个具体的例子中,“运行 3 次”只会在你第一次运行代码时发生——之后,状态已经完全同步,从那时起它只会触发一次。此行为在此处详细说明:https ://www.firebase.com/docs/transactions.html (请参阅“运行事务时,会发生以下情况”部分。)

例如,如果您在同一位置有一个未完成的 on(),然后在稍后的某个时间运行相同的事务代码,您会看到它只运行一次。这是因为在事务运行之前一切都是同步的(在理想情况下;除非有任何正常的冲突等)。

于 2013-04-21T02:36:45.543 回答
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');
});
于 2017-11-13T07:52:19.520 回答