我正在使用rxjs为智能电视上的遥控器创建“频道数量”选择器。我们的想法是,当您输入数字时,您会在屏幕上看到它们,在您输入数字后,用户实际上会被带到该频道。
我使用两个observable来实现这个目标:
一个“进度”流,它会侦听所有数字输入,并在数字通过扫描操作符输入时发出连接的数字字符串。
一个“已完成”的流,在没有输入数字的n毫秒之后,将完成最终的数字字符串。 EG:1-2-3 - > “123”。
以下是我用来尝试解决此问题的代码:
的channelNumber:
module.exports = function (numberKeys, source, scheduler) {
return function (completedDelay) {
var toNumericString = function (name) {
return numberKeys.indexOf(name).toString();
},
concat = function (current, numeric) {
return current.length === 3 ? current : current + numeric;
},
live = createPress(source, scheduler)(numberKeys)
.map(toNumericString)
.scan(concat, '')
.distinctUntilChanged(),
completed = live.flatMapLatest(function (value) {
return Rx.Observable.timer(completedDelay, scheduler).map(value);
}),
progress = live.takeUntil(completed).repeat();
return {
progress: progress,
completed: completed
};
};
};
createPress:
module.exports = function (source, scheduler) {
return function (keyName, throttle) {
return source
.filter(H.isKeyDownOf(keyName))
.map(H.toKeyName);
};
};
createSource:
module.exports = function (provider) {
var createStream = function (event) {
var filter = function (e) {
return provider.hasCode(e.keyCode);
},
map = function (e) {
return {
type: event,
name: provider.getName(e.keyCode),
code: e.keyCode
};
};
return Rx.Observable.fromEvent(document, event)
.filter(filter)
.map(map);
};
return Rx.Observable.merge(createStream('keyup'), createStream('keydown'));
};
有趣的是,上面的代码,在测试条件下(使用Rx.TestScheduler的模拟源和调度程序)按预期工作。但是在生产中,当调度程序根本没有传递而源是createPress(上面)的结果时,进度流只会发送直到完成,然后再也不会发生。就像重复被完全忽略或冗余一样。我不明白为什么。
我在这里错过了什么吗?
答案 0 :(得分:1)
您可以使用Window。在这种情况下,我建议WindowWithTime。您还可以执行更多有趣的操作,例如使用Window(windowBoundaries),然后使用Debounce作为边界传递来源。
source
.windowWithTime(1500)
.flatMap(ob => ob.reduce((acc, cur) => acc + cur, ""))
此外,由于我们的窗口是封闭的可观察对象,我们可以使用Reduce从窗口累积值并连接我们的数字。
现在,这个变种将在1.5秒后关闭。相反,我们希望在最后一次按键后等待x秒。 Naïve我们可以做source.window(source.debounce(1000))
但是现在我们订阅了两次我们的来源,这是我们想要避免的两个原因。首先我们不知道订阅是否有任何副作用,第二我们不知道订阅订阅会收到事件。最后一件事不是问题,因为我们使用的debounce在最后一次按键后已经增加了延迟,但仍需要考虑。
解决方案是publish我们的来源。为了将发布保留在序列中,我们将其包装到observable.create。
Rx.Observable.create(observer => {
var ob = source.publish();
return new Rx.CompositeDisposable(
ob.window(ob.debounce(1000))
.subscribe(observer),
ob.connect());
}).flatMap(ob => ob.reduce((acc, cur) => acc + cur, ""))
修改:或者像这样使用publish
:
source.publish(ob => ob.window(ob.debounce(1000)))
.flatMap(ob => ob.reduce((acc, cur) => acc + cur, ""))