RXJS - 仅在空闲时启动计时器?

时间:2017-04-20 17:38:11

标签: javascript rxjs rxjs5

我使用的是当我滚动窗口时受到限制的流 在限制时(只要滚动),它会向控制台发送值。

然而,当流空闲时(用户滚动窗口) - 我想要一个计时器启动。但是 - 如果用户再次开始滚动 - 我不想要那个计时器发出值。

目前我正在这样做:

  const observable = Rx.Observable.fromEvent(window, 'scroll');

  const subscriber = observable
      .throttleTime(300 )
      .map(() => 'throttle')
      .merge(Rx.Observable.interval(1000).map(() => 'tick') )
      .subscribe(
          (x) => {
            console.log('Next: event!', x);
          },
          (err) => {
            console.log('Error: %s', err);
          },
          () => {
            console.log('Completed');
          });

问题是,在滚动时 - 我看到"throttle""tick"(我应该只看到"油门")

从另一个POV想想这个。工作总是必须运行。如果我滚动 - 那个受限制的滚动 - 应该调用这个工作。如果我不滚动 - 计时器应该启动并开始完成工作。 (如果用户再次开始滚动,则停止。)

问题:
如何在不滚动的空闲时间后启动计时器?

PLNKR

2 个答案:

答案 0 :(得分:3)

您可以使用debounceTime检测句点而无需滚动。

const scroll = Rx.Observable.fromEvent(window, 'scroll')
  .throttleTime(300)
  .mapTo(false);
const noscroll = Rx.Observable.fromEvent(window, 'scroll')
  .startWith(0) // init with no scroll.
  .debounceTime(300) // detect no scroll after 300 ms.
  .mapTo(true);
scroll.merge(noscroll)
  .switchMap(e => e ? Rx.Observable.interval(1000).mapTo("Tick!") : Rx.Observable.of("Scroll!"))  
  // start the interval if there was no scroll. Stop the interval if there was a scroll.
  .subscribe(updateTimer)

你的代码的另一个问题是使用merge来保持两个源都订阅,而我使用switchMapmergeMap的兄弟),每次订阅内部observable如果从源发出另一个事件,则会发出新事件,但也取消订阅前一个内部源。

Re:"另一个POV"部分问题:您可以将Rx.Observable.interval(1000)中的switchMap替换为该作业。滚动将取消/取消订阅作业(发出empty),如果没有更多滚动,则作业将重新开始。

Live demo

答案 1 :(得分:2)

我会这样做:

const scroll$ = Rx.Observable.fromEvent(window, 'scroll')
    .throttleTime(300 /* ms */)
    .publish();

scroll$.connect();

const subscriber = scroll$
    .map(() => 'throttle')
    .race(Rx.Observable.interval(1000).map(() => 'tick'))
    .take(1)
    .repeat()
    .subscribe(
        (x) => {
          console.log('Next: event!', x);
        },
        (err) => {
          console.log('Error: %s', err);
        },
        () => {
          console.log('Completed');
        });

这使用race()运算符仅订阅首先发出的1s interval或滚动事件的Observable。在那之后我想用另一个间隔重新开始这个,所以我使用take(1).repeat()

我还必须将scroll$ Observable变成一个热门的Observable,以使throttleTime()在重复的订阅中保持运行。

您的最新演示:https://plnkr.co/edit/sWzSm32uoOQ1hOKigo4s?p=preview