【问题标题】:How do I timeout an event in RxJS?如何使 RxJS 中的事件超时?
【发布时间】:2014-06-01 23:06:21
【问题描述】:

我正在尝试检测mousedown 事件是否在mouseup 之前举行了一段时间。

我在使用fromEvent() 创建的 Observable 上使用 timeout() 来执行此操作,但超时会返回两个 Observable。

下面,如果mousedown在1秒内被触发,订阅流返回事件,但它也返回1。

var mousedown = Rx.Observable.fromEvent(target, 'mousedown');
var stream = mousedown.timeout(1000, Rx.Observable.return(1));

var sub = stream.subscribe(
    function (x) { 
        console.log('Next: '+x);
    },
    function (err) {
        console.log('Err: '+err);
    },
    function () {
        console.log('Complete');
    }
);

但是,这按预期工作:

var source = Rx.Observable.return(42)
    .delay(200)
    .timeout(1000, Rx.Observable.return(1));

我希望这段代码可以工作:

var mousedown = Rx.Observable.fromEvent(target, 'mousedown');
var mouseup = Rx.Observable.fromEvent(target, 'mouseup');

var clickhold = mousedown
.flatMap(function (){
    return mouseup.timeout(1000, Rx.Observable.return('hold'));
})
.filter(function (x) {
    return x === 'hold';
});

clickhold.subscribe(
    function (x) { 
        console.log('Next: '+x);
    },
    function (err) {
        console.log('Err: '+err);
    },
    function () {
        console.log('Complete');
    }
);

【问题讨论】:

    标签: rxjs


    【解决方案1】:

    我没有使用timeout,而是使用delaytakeUntil

    var target,
        mousedown,
        mouseup;
    
    target = document.querySelector('input');
    
    mousedown = Rx.Observable.fromEvent(target, 'mousedown');
    mouseup = Rx.Observable.fromEvent(target, 'mouseup');
    
    var clickhold = mousedown
        .flatMap(function(){
            // Triggered instantly after mousedown event.
            return Rx.Observable
                .return('hold')
                .delay(1000)
                // Discards the return value if by the time .delay() is complete
                // mouseup event has been already completed.
                .takeUntil(mouseup);
        });
    
    clickhold.subscribe(
            function (x) { 
                console.log('Next: ' + x);
            },
            function (err) {
                console.log('Err: ' + err);
            },
            function () {
               console.log('Complete');
            }
        );
    <script src='https://rawgit.com/Reactive-Extensions/RxJS/v.2.5.3/dist/rx.all.js'></script>
    
    <input type='button' value='Button' />

    【讨论】:

      【解决方案2】:

      您自己想出了一个很好的解决方案。以下是我要更改的内容:

      1. 将内部 observable (timer(...).takeUntil(...).select(...)) 移出 flatMap,因此不会为每个鼠标按下重新分配。

      其余的你都做对了。对于我的使用,我通常保留原始的mousedown 事件并使用它而不是'hold'。这需要returnValuedelay 而不是timerselect

      var target,
          mousedown,
          mouseup;
      
      target = document.querySelector('input');
      
      mousedown = Rx.Observable.fromEvent(target, 'mousedown');
      mouseup = Rx.Observable.fromEvent(target, 'mouseup');
      
      var clickhold = mousedown
          .flatMap(function (e) {
              return Rx.Observable
                  .return(e)
                  .delay(1000)
                  .takeUntil(mouseup);
          });
      
      clickhold.subscribe(function (x) { 
              console.log('onNext: ', x);
          });
      <script src='https://rawgit.com/Reactive-Extensions/RxJS/v.2.5.3/dist/rx.all.js'></script>
      
      <input type='button' value='Button' />

      或者,换一种完全不同的方法……

      var Observable  = Rx.Observable,
          fromEvent   = Observable.fromEvent.bind(Observable, target),
          holdDelay   = Observable.empty().delay(1000);
      
      Observable
        .merge(
          [
            fromEvent('mouseup')
              .map(empty),
            fromEvent('mousedown')
              .map(Observable.returnValue)
              .map(holdDelay.concat.bind(holdDelay))
          ]
        )
        .switchLatest();
      

      好的,这很奇怪。不过,我真的只是把它当作食物,并炫耀这可以通过多种不同的方式完成。

      【讨论】:

      • 谢谢!我也在考虑使用 switchLatest,您的示例清楚地说明了我如何使用它。
      • 作为后续,您将如何在“clickhold”之后检查 mouseup?我正在订阅 Observable.when(clickhold.and(mouseup).then(function(){ return 'release';}), mouseup.then(function(){ return 'mouseup';}),以反转状态。
      • 我对你的问题有点困惑。在谈论基于同步拉的系统时,诸如“检查”之类的措辞非常有效,但是当我们谈论事件时,我很难理解它。能改一下吗?
      • 基本上我想检查'clickhold'序列是否后跟一个mouseup。例如,如果我单击一个框并更改其颜色,然后在 mouseup 上我想将颜色更改回来。我这里有一个使用 when() 的解决方案:codepen.io/geekrelief/pen/FAimL?editors=101 但我想知道是否有更简洁的方法。
      • 您可能对 Paul Taylor 的 RxJS 统一手势库感兴趣。 github.com/trxcllnt/rxjs-gestures
      猜你喜欢
      • 2014-11-08
      • 1970-01-01
      • 2017-03-20
      • 2023-03-31
      • 1970-01-01
      • 2017-06-11
      • 1970-01-01
      • 2017-03-16
      • 2015-04-13
      相关资源
      最近更新 更多