这是一个相当复杂的问题,但我会试着简单地解释一下这个问题。我可以简明扼要地......
我正在使用Firebase构建一个基于Web的多用户游戏。我保留了游戏中每一轮的清单。在一轮结束时,每个用户都会看到一个“开始”按钮,当他们准备开始下一轮时,他们会点击该按钮。当至少50%的用户点击“开始”时,该轮开始。
我为游戏提供了Firebase引用gameRef
,代表轮次列表的引用roundListRef
和代表当前回合的引用roundRef
。
我已将child_added
回调附加到roundListRef
,以便在添加新回合时,它成为每个人的当前回合:
roundListRef.on('child_added', function(childSnapshot, prevChildName) {
roundRef = childSnapshot.ref();
});
我可以跟踪newRoundVotes
和activePlayers
,并从那里轻松计算50%。如果达到50%,则会添加新一轮,触发每个人的child_added
事件,新一轮将从那里开始......
gameRef.child('newRoundVotes').on('value', function(snapshot) {
var newRoundVotes = snapshot.val();
gameRef.child('activePlayers').once('value', function(snapshot) {
var activePlayers = snapshot.val();
if (newDriveVotes / activePlayers >= 0.5)
addNewRound();
});
});
我的问题是,如何确保只添加一轮新轮次,并且每个人都在同一轮?
例如,假设有10名球员,4名已经投票开始下一轮比赛。如果第6名玩家在第5名玩家触发child_added
事件之前投票,那么第6名玩家也将获得一轮回合。
问题类似于.set()
vs .transaction()
,但不完全相同(根据我的理解)。
有没有人有解决方案?
答案 0 :(得分:6)
如果圆形名称提前知道,我认为您可以通过交易解决此问题。例如。如果你只使用/ round / 0,/ round / 1,/ round / 2等
然后你可以有一些代码:
function addNewRound() {
var currentRound = Number(roundRef.name());
var nextRound = currentRound + 1;
// Use a transaction to try to create the next round.
roundRefList.child(nextRound).transaction(function(newRoundValue) {
if (newRoundValue == null) {
// create new round.
return { /* whatever should be stored for the round. */ };
} else {
// somebody else already created it. Do nothing.
}
});
}
这适合您的情况吗?
答案 1 :(得分:1)
您可以稍微修改一下您的想法,并使用圆形计数器作为跟踪并发的地方。
currentRound = 0;
currentRoundRef.on('value', function(snapshot) {
currentRound = snapshot.val();
roundRef = roundListRef.child(currentRound);
});
function addNewRound() {
currentRoundRef.transaction( function(current_value) {
if( current_value !== currentRound ) {
// the round timer has been updated by someone else
return;
}
else {
return currentRound + 1;
}
}, function(success) {
// called after our transaction succeeds or fails
if( success ) {
roundListRef.child(currentRound+1).set(...);
}
});
}