2012-08-02 1 views
4

C'est une question assez complexe, mais je vais essayer de l'expliquer comme une simple & de façon concise que je peux ...Fonctionnalité Firebase transactionnelle() lors de l'ajout à une liste?

J'utilise Firebase pour construire un multi-utilisateurs, jeu basé sur le Web. Je garde une liste de tous les tours du jeu. À la fin d'un tour, chaque utilisateur reçoit un bouton «Démarrer» sur lequel il clique lorsqu'il est prêt à commencer le tour suivant. Le tour commence quand au moins 50% des utilisateurs ont cliqué sur "Démarrer".

J'ai une référence Firebase gameRef pour le jeu, une référence roundListRef qui représente la liste des tours, et une référence roundRef qui représente le tour en cours.

Je joins un rappel child_added-roundListRef de sorte que quand un nouveau cycle est ajouté, il devient courant de tout le monde autour de:

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

Je peux suivre newRoundVotes et activePlayers, et calculer 50% facilement à partir de là. Si 50% est atteint, un nouveau cycle est ajouté, ce qui déclenche l'événement de tout le monde child_added et le nouveau cycle commencera à partir de là ...

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

Ma question est, comment puis-je assurer que seul un nouveau cycle est ajouté , et que tout le monde est sur le même tour? Par exemple, disons qu'il y a 10 joueurs et que 4 ont déjà voté pour commencer le tour suivant. Par exemple, disons qu'il y a 10 joueurs. Si le 6ème joueur vote avant que son événement child_added ne soit déclenché par le 5ème joueur, alors un tour sera également ajouté pour le 6ème joueur.

Le problème est similaire à .set() vs .transaction(), mais pas tout à fait la même chose (d'après ce que je comprends).

Est-ce que quelqu'un a une solution?

Répondre

6

Je pense que vous pouvez probablement résoudre cela avec une transaction si les noms ronds sont connus à l'avance. Par exemple. si vous utilisez seulement/rond/0,/rond/1,/tour/2, etc.

alors vous pourriez avoir un code comme:

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

Est-ce que ce travail pour votre scénario?

+0

Ha! C'est tellement plus simple. Je n'avais même pas considéré que vous pouviez simplement utiliser 'transaction' sur un enfant qui n'existe pas encore. – Kato

+0

Oui, c'est une bonne idée! J'ai utilisé push() juste parce que c'était une liste et je n'avais même pas pensé à faire quelque chose comme ça. Merci. –

1

Vous pourriez modifier légèrement votre façon de penser et utiliser un compteur rond pour suivre la simultanéité.

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