2017-04-20 13 views
5

我正在使用當我滾動窗口時被扼流的流。
限制(只要滾動),它會向控制檯發出值。但是,當流空閒(用戶是而不是滾動窗口) - 我想要一個計時器踢入。但是 - 如果用戶再次開始滾動 - 我不希望該計時器發出值。RXJS - 僅在閒置時啓動計時器?

目前我在做這個:

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

這是如何使一個很好的問題上左右。 +1 –

+0

Re [your other comment](http://stackoverflow.com/questions/41522222/making-a-typing-timer-in-rxjs-tracking-time-spent-typing/41526650?noredirect=1#comment74109988_41526650) :你可以使用'exhaustMap' +'debounceTime'中的技巧解決這個問題,以檢測沒有滾動。我在'switchMap'上做了什麼,因爲我們在突發事件期間什麼都不做,並且當流空閒時工作就發生了。相反,'switchMap'會在每次發生新的滾動事件時重新啓動作業(定時器)。 – Dorus

回答

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()操作人員只需訂閱發出第一這是1秒interval或滾動事件的觀測。在此之後,我想以另一個時間間隔再次開始,所以我使用take(1).repeat()

我還必須將scroll$ Observable轉換爲熱點Observable,以使throttleTime()在重複訂閱中運行。

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

+0

我可以問'publish()。Connect()'與你在這裏做的是什麼不同?'publish()。refcount()'{which'share()'} –

+0

@Royi connect() '不是每個說的操作符(它不返回一個Observable)。它只是'ConnectableObservable'類的一個方法,它返回一個'Subscription',你可以用它來「斷開連接」。它與'subscribe()'方法類似,您可以使用運算符鏈接,但它也會返回'Subscription'。這意味着它只能在運營商鏈的末端使用。 'refCount()'另一方面返回另一個Observable,所以你可以將它與其他操作符鏈接起來。 – martin

+0

馬丁,你已經通過連接使這個可觀察的變得很熱。但如果我把它改成'.share()'(這也是使它變熱的另一種方式) - 然後 - 在滾動時 - 它似乎不遵守'節流閥延遲。這是爲什麼 ? https://plnkr.co/edit/jjWUxbk9fSItLT1U7uiq?p=preview –

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,將讓兩個源認購,而不是我使用switchMap(的mergeMap兄弟姐妹),其將認購新事件發出內部觀察到的每一次,而且退訂如果從源發出另一個事件,則爲之前的內部源。

回覆:「另一個POV」問題的一部分:您可以用switchMap替換Rx.Observable.interval(1000)作業。滾動將取消/取消訂閱作業(如發出empty),如果不再滾動,作業將再次開始。

Live demo

+0

看到這兩個plunkrs(2種方法)將會很棒 –

+0

在你的回答代碼中,當我滾動https://plnkr.co/edit/JX3QCjj6a9sBPM4fivZL?p=preview –

+0

:-)時,我看不到任何排放物[I覺得我不止一次寫過](https://i.imgur.com/HfcsRt5.jpg) –