2

我正在试验 RxJS(带有 JQuery 扩展),我正在尝试解决以下用例:

鉴于我有两个按钮(A 和 B),如果在给定的时间范围内单击某个“秘密组合”,我想打印一条消息。例如,“秘密组合”可以是在 5 秒内点击“ABBABA”。如果在 5 秒内未输入该组合,则应显示超时消息。这是我目前拥有的:

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!");
    }
});

虽然这工作得很好,但这并不是我想要的。bufferWithTimeOrCount在新的时间范围内第一次按下按钮 A 时,我需要重置 。我正在寻找的是,一旦按下秘密组合(ABBABA),我就会想要“组合解锁!” 显示(我不想等待时间窗口过期)。

4

1 回答 1

7

Throttle是您想要的具有反应性重置效果的延迟的典型运算符。

以下是如何结合使用节流阀和扫描来收集在 5 秒静音之前输入的组合:

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) 我们scan将输入的字符连接起来。(2) Throttle 等待 5 秒的事件静默并发出静默之前的最后一个事件。换句话说,它类似于延迟,除了它会在源 Observable 上看到新事件时重置内部计时器。我们需要重置扫描的串联 (1),因此我们只需将相同的节流 Observable 映射到“重置”标志 (3),扫描将其解释为清除累加器 ( acc)。

这是一个JSFiddle

于 2014-09-14T20:23:39.717 回答