Firebase事务() - 添加到列表时的功能类似?

时间:2012-08-02 21:59:02

标签: firebase

这是一个相当复杂的问题,但我会试着简单地解释一下这个问题。我可以简明扼要地......

我正在使用Firebase构建一个基于Web的多用户游戏。我保留了游戏中每一轮的清单。在一轮结束时,每个用户都会看到一个“开始”按钮,当他们准备开始下一轮时,他们会点击该按钮。当至少50%的用户点击“开始”时,该轮开始。

我为游戏提供了Firebase引用gameRef,代表轮次列表的引用roundListRef和代表当前回合的引用roundRef

我已将child_added回调附加到roundListRef,以便在添加新回合时,它成为每个人的当前回合:

roundListRef.on('child_added', function(childSnapshot, prevChildName) {
    roundRef = childSnapshot.ref();
});

我可以跟踪newRoundVotesactivePlayers,并从那里轻松计算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(),但不完全相同(根据我的理解)。

有没有人有解决方案?

2 个答案:

答案 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(...);
       }
    });
}