问题描述
我正在尝试使用RxJS(使用JQuery扩展)并且我正在尝试解决以下用例:
I'm experimenting with RxJS (with the JQuery extension) and I'm trying to solve the following use case:
鉴于我有两个按钮(A & B)如果在给定的时间范围内点击某个秘密组合,我想打印一条消息。例如,秘密组合可以是在5秒内点击ABBABA。如果未在5秒内输入组合,则应显示超时消息。这就是我目前所拥有的:
Given that I have two buttons (A & B) I'd like to print a message if a certain "secret combination" is clicked within a given timeframe. For example the "secret combination" could be to click "ABBABA" within 5 seconds. If the combination is not entered within 5 seconds a timeout message should be displayed. This is what I currently have:
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!");
}
});
虽然效果相当好,但这并不是我想要的。我需要在新的时间范围内第一次按下按钮A时重置 bufferWithTimeOrCount
。我正在寻找的是,只要按下秘密组合(ABBABA),我就会想要组合解锁!显示(我不想等待时间窗口过期)。
While this works fairly well it's not exactly what I want. I need the bufferWithTimeOrCount
to be reset when button A is pressed for the first time in a new timeframe. What I'm looking for is that as soon as the secret combination is pressed (ABBABA) I'd like "Combination unlocked!" to be shown (I don't want to wait for the time window to be expired).
推荐答案
是延迟反应重置效果的典型操作符。
Throttle is the typical operator for the delaying with reactive resetting effect you want.
以下是如何使用油门与扫描相结合来收集在5秒静音之前输入的组合:
Here's how you can use throttle in combination with scan to gather the combination inputted before the 5 seconds of 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)我们扫描
连接输入字符。 (2)油门等待事件静音5秒钟,并在沉默之前发出最后一个事件。换句话说,它类似于延迟,除了它在源Observable上看到新事件时重置内部计时器。我们需要重置扫描的连接(1),因此我们只需将相同的限制Observable映射到reset标志(3),扫描将其解释为清除累加器( acc
)。
(1) We scan
to concatenate the input characters. (2) Throttle waits for 5 seconds of event silence and emits the last event before that silence. In other words, it's similar to delay, except it resets the inner timer when a new event is seen on the source Observable. We need to reset the scan's concatenation (1), so we just map the same throttled Observable to "reset" flags (3), which the scan will interpret as clearing the accumulator (acc
).
这是一个。
这篇关于使用RxJS重置事件超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!