【问题标题】:How can I filter a stream only when it changes?如何仅在流更改时过滤流?
【发布时间】:2015-11-19 13:46:58
【问题描述】:

响应式编程的新手。我有一个流,一个滚动流,绑定到一个 domNode,然后还有一些其他流通过过滤器订阅:

var element = document.getElementById('scrollableElement');
var sourceStream = Rx.Observable.fromEvent(element, 'scroll').map(function(e){
  return e.srcElement.scrollTop;
});

var inTheOneHundreds = sourceStream
  .filter(function (x, idx, obs) {
    return x >= 100 && x < 200;
  });

var inTheTwoHundreds = sourceStream
  .filter(function (x, idx, obs) {
    return x >= 200 && x < 300;
  });

inTheOneHundreds.subscribe(function(value){
  console.log('one hundreds ' + value);
});

inTheTwoHundreds.subscribe(function(value){
  console.log('two hundreds ' + value);
});

这样的输出:

one hundreds 193
one hundreds 196
one hundreds 199
two hundreds 201
two hundreds 204

你可以在这里看到这个:http://jsbin.com/zedazapato/edit?js,console,output

我希望这些新流在数百个变化时输出(从truefalse),而不是重复输出:

one hundreds 199
two hundreds 201
one hundreds 170
two hundreds 270
one hundreds 103
two hundreds 200
one hundreds 156

我尝试过使用Observable.distinctUntilChanged,但它的行为似乎不像我预期的那样(它似乎输出相同的东西):http://jsbin.com/gibefagiri/1/edit?js,console,output

我哪里出错了?

【问题讨论】:

    标签: javascript reactive-programming reactive-streams


    【解决方案1】:

    您有多种选择。

    这将从谓词生成流,当谓词为真时发出一个项目:

    var element = document.getElementById('scrollableElement');
    var sourceStream = Rx.Observable.fromEvent(element, 'scroll').map(function(e){
      return e.srcElement.scrollTop;
    });
    
    function whenBecomesTrue(stream, selector) {
      return stream.distinctUntilChanged(selector).filter(selector);
    }
    
    var inTheOneHundreds = whenBecomesTrue(sourceStream, function (x, idx, obs) {
      return x >= 100 && x < 200;
    });
    
    var inTheTwoHundreds = whenBecomesTrue(sourceStream, function (x, idx, obs) {
      return x >= 200 && x < 300;
    });
    
    inTheOneHundreds.subscribe(function(value){
      console.log('one hundreds ' + value);
    });
    
    inTheTwoHundreds.subscribe(function(value){
      console.log('two hundreds ' + value);
    });
    

    或者您可以先发出页面更改:

    var element = document.getElementById('scrollableElement');
    var sourceStream = Rx.Observable.fromEvent(element, 'scroll').map(function(e){
      return e.srcElement.scrollTop;
    });
    
    function pageOf(x) {
      return Math.floor(x / 100);
    }
    
    var pageChanges = sourceStream.distinctUntilChanged(pageOf);
    
    var inTheOneHundreds = pageChanges.filter(function (x, idx, obs) {
      return pageOf(x) === 1;
    });
    
    var inTheTwoHundreds = pageChanges.filter(function (x, idx, obs) {
      return pageOf(x) === 2;
    });
    
    inTheOneHundreds.subscribe(function(value){
      console.log('one hundreds ' + value);
    });
    
    inTheTwoHundreds.subscribe(function(value){
      console.log('two hundreds ' + value);
    });
    

    您使用 distinctUntilChanged 的​​方法的问题在于,它实际上与原始 scrollTop 值(始终不同于前一个值)不同,而不是指示数字是否在给定范围内的布尔值。

    【讨论】:

    • 谢谢。清晰得多。我不太明白你最后的评论。 distinctUntilChanged 是否适用于原始源流,而不是使用 mapfilter 创建的任何中间流?
    • 不,它确实适用于映射和过滤的流。您希望它区分 true-false 值,但它区分实际数字 200,201,202...,因为这是过滤器返回的内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-01
    • 2020-05-01
    • 2021-10-28
    相关资源
    最近更新 更多