【问题标题】:Firebase transaction()-like functionality when adding to a list?添加到列表时类似于 Firebase 事务()的功能?
【发布时间】:2012-08-03 06:40:14
【问题描述】:

这是一个相当复杂的问题,但我会尽量简明扼要地解释它......

我正在使用 Firebase 构建一个基于网络的多用户游戏。我保留了游戏中每一轮的列表。在一轮结束时,每个用户都会看到一个“开始”按钮,当他们准备好开始下一轮时,他们会单击该按钮。当至少 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 位玩家在他的child_added 事件被第 5 位玩家触发之前投票,那么也会为第 6 位玩家添加一轮。

问题类似于.set() vs .transaction(),但不完全相同(根据我的理解)。

有人有解决办法吗?

【问题讨论】:

    标签: firebase


    【解决方案1】:

    如果提前知道回合名称,我认为您可以通过交易解决这个问题。例如。如果你只使用 /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.
            }
        });
    }
    

    这适用于您的场景吗?

    【讨论】:

    • 哈!这样就简单多了。我什至没有考虑过你可以对一个还不存在的孩子使用transaction
    • 是的 - 好主意!我一直在使用 push() 只是因为它是一个列表,甚至没有想过做这样的事情。谢谢。
    【解决方案2】:

    您可以稍微修改一下您的想法,并使用圆形计数器作为跟踪并发的地方。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-29
      • 1970-01-01
      • 2013-04-18
      • 2020-04-17
      • 1970-01-01
      • 2012-12-15
      • 1970-01-01
      • 2012-10-04
      相关资源
      最近更新 更多