2014-09-14 4 views
2

J'expérimente avec RxJS (avec l'extension JQuery) et je suis en train de résoudre le cas d'utilisation suivante:délai de réinitialisation sur l'événement avec RxJS

Étant donné que j'ai deux boutons (A & B) Je J'aime imprimer un message si l'on clique sur une certaine "combinaison secrète" dans un laps de temps donné. Par exemple, la "combinaison secrète" pourrait être de cliquer sur "ABBABA" dans les 5 secondes. Si la combinaison n'est pas entrée dans les 5 secondes, un message de délai d'attente devrait être affiché. C'est ce que j'ai actuellement:

var secretCombination = "ABBABA"; 

var buttonA = $("#button-a").clickAsObservable().map(function() { return "A"; }); 
var buttonB = $("#button-b").clickAsObservable().map(function() { return "B"; }); 

var bothButtons = Rx.Observable.merge(buttonA, buttonB); 

var outputDiv = $("#output"); 

bothButtons.do(function (buttonName) { 
    outputDiv.append(buttonName); 
}).bufferWithTimeOrCount(5000, 6).map(function (combination) { 
    return combination.reduce(function (combination, buttonName) { 
     return combination + buttonName; 
    }, ""); 
}).map(function (combination) { 
    return combination === secretCombination; 
}).subscribe(function (successfulCombination) { 
    if (successfulCombination) { 
     outputDiv.html("Combination unlocked!"); 
    } else { 
     outputDiv.html("You're not fast enough, try again!"); 
    } 
}); 

Bien que cela fonctionne assez bien, ce n'est pas exactement ce que je veux. J'ai besoin que le bufferWithTimeOrCount soit réinitialisé lorsque le bouton A est enfoncé pour la première fois dans une nouvelle période. Ce que je cherche, c'est que dès que la combinaison secrète est pressée (ABBABA), je voudrais "Combined unlocked!" être montré (je ne veux pas attendre que la fenêtre de temps soit expirée).

Répondre

7

Throttle est l'opérateur typique pour le retardant avec réinitialisation réactive effet que vous voulez.

Voici comment vous pouvez utiliser des gaz en combinaison avec le balayage pour recueillir la combinaison avant les entrées 5 secondes de silence:

var evaluationStream = bothButtons 
    .merge(bothButtons.throttle(5000).map(function(){return "reset";})) // (2) and (3) 
    .scan(function(acc, x) { // (1) 
    if (x === "reset") return ""; 
    var newAcc = acc + x; 
    if (newAcc.length > secretCombination.length) { 
     return newAcc.substr(newAcc.length - secretCombination.length); 
    } 
    else { 
     return newAcc; 
    } 
    }) 
    .map(function(combination) { 
    return combination === secretCombination; 
    }); 

var wrongStream = evaluationStream 
    .throttle(5000) 
    .filter(function(result) { return result === false; }); 

var correctStream = evaluationStream 
    .filter(function(result) { return result === true; }); 

wrongStream.subscribe(function() { 
    outputDiv.html("Too slow or wrong!"); 
}); 

correctStream.subscribe(function() { 
    outputDiv.html("Combination unlocked!"); 
}); 

(1) Nous scan concaténer les caractères d'entrée. (2) Throttle attend 5 secondes de silence d'événement et émet le dernier événement avant ce silence. En d'autres termes, il est similaire au délai, sauf qu'il réinitialise le temporisateur interne lorsqu'un nouvel événement est vu sur la source Observable. Nous devons réinitialiser la concaténation de l'analyse (1), de sorte que nous ne faisons que mapper le même Observable étranglé aux indicateurs de réinitialisation (3), que l'analyse interprétera comme l'effacement de l'accumulateur (acc). Il s'agit d'un JSFiddle.

+0

Merci beaucoup pour votre réponse détaillée. C'est une bonne amélioration mais ce n'est pas exactement ce que je cherche (peut-être la question est un peu floue, je vais éditer la question). Si vous allez à la page JSFiddle et cliquez sur "BBABBABA" vous obtenez "Trop lent ou faux!". Je veux que ce soit correct puisque vous avez en effet cliqué sur ABBABA (je m'en fous que BB ait été cliqué avant ABBABA). Aussi, je voudrais "Combinaison débloqué!" à afficher instantanément après avoir appuyé sur ABBABA. Je ne veux pas attendre que la fenêtre de temps ait expiré. – Johan

+0

Alors pourquoi avez-vous besoin des "5 secondes"? Pourquoi ne pas simplement concaténer les caractères dans l'analyse, et prendre les 6 derniers caractères à comparer dans la carte suivante? –

+0

Parce que je veux toujours que la combinaison secrète soit entrée dans les 5 secondes une fois initiée. Disons que j'ai appuyé sur "BB" et maintenant j'appuie sur "A". J'ai maintenant 5 secondes pour appuyer sur le "BBABA" restant. Si un délai d'attente ou une mauvaise entrée se produit, je dois redémarrer. – Johan

Questions connexes