2013-04-20 51 views
4

每當我在NodeJS中定義一個Firebase事務時,我發現它總是運行三次 - 前兩次使用空數據,最後第三次使用實際數據。這是正常的嗎?NodeJS中的Firebase事務始終運行3次?

例如下面的代碼:

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虛像這樣:

firebaseOOO.child('ref').transaction(function(data) { 
    console.log('hit'); 
    return data; 
}, function(){}, false); 

但它仍然打3次(只是雙重檢查),所以我認爲這是不同的東西。在交易之前獲得'價值'會像預期的那樣「起作用」,因爲它只會觸及一次,而且不管侷限性是什麼,所以我不確定適用於什麼?這就是我所說的交易之前所獲得的價值是指:

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

輸出:

1 
2 

@邁克爾:一個人如何可以利用的這種行爲?事務主要用於讓數據本身用於自我修改 - 原型增量++方案。所以如果我需要給現有值10加1,並繼續使用11的結果,函數命中的前兩次我將得到我需要處理的錯誤結果1,最後得到正確的結果第三次打11。我怎樣才能使用這兩個最初的1?另一種情況(也許我不應該爲此使用事務,但如果它像我期望的那樣工作,它會使代碼變得更清晰)是如果值不存在,則插入一個值。如果事務只觸發一次,則空值意味着該值不存在,因此您可以在該情況下將計數器初始化爲1,否則將值加1。用嘈雜的零點,這是不可能的。

這似乎是從這一切的外賣是簡單地使用'一次'模式更經常?

ONCE交易模式:

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

這是一個很奇怪的交易用途。你爲什麼要把它設回到完全相同的值?如果你設置了第二個回調,它說什麼?提交成功了嗎?有錯誤嗎? – Kato 2013-04-20 13:43:11

+0

嘿加藤,這是證明我的問題絕對最簡單的情況。我真正的代碼有更多的邏輯。沒有錯誤信息,結果在最後成功記錄。事實上,如預期的那樣,最終只有1個提交消息。我更新了我的問題以反映這些結果。 – Baz 2013-04-20 20:47:07

回答

2

你在這裏看到的行爲與火力地堡如何觸發本地事件,然後最終與火力地堡服務器同步。在這個特定的例子中,「運行三次」只會在你第一次運行代碼時發生 - 在這之後,狀態已經完全同步,並且從那時起只會觸發一次。此行爲在此處詳述如下:請參閱「執行事務時發生以下情況」一節。)

例如,如果您在同一位置有一個未完成的on(),並且稍後時間,運行這個相同的事務代碼,你會看到它只會運行一次。這是因爲所有事務在事務運行之前都處於同步狀態(理想情況下,禁止任何正常衝突等)。

+1

如何區分由於所描述的內部事件而產生的空值與在Firebase中尚不存在對象的「真實」空值? – Baz 2013-04-21 04:01:58

+2

您可以在相同的位置爲「value」事件添加偵聽器,並在事務處理調用中將applyLocally設置爲false。這樣,一旦設置了事務的最終值,您的值事件偵聽器就會觸發。 請參閱此處的交易文檔,查找applyLocally參數:https://www.firebase.com/docs/javascript/firebase/transaction.html – 2013-04-21 20:52:07

+1

此外,我會對您的用例感興趣,並且如果空值實際上造成麻煩。現在我們樂觀地運行事務,然後才能將數據同步,這就是爲什麼您會看到'null',並且迄今爲止這一切都非常成功。但我們考慮改變行爲。如果您有興趣分享有關您的用例的更多詳細信息,請在firebase com中Ping邁克爾! – 2013-04-22 16:20:29

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'); 
});