2017-04-20 22 views
5

Używam strumienia, który jest dławiony po przewinięciu okna.
Podczas dławienia (tak długo, jak przewijanie), wysyła wartości do konsoli.RXJS - uruchamiać timer tylko wtedy, gdy nie jest używany?

Jednak, gdy strumień jest bezczynny (użytkownik jest nie przewijanie okna) - Chcę, aby zegar do kick. Jednak - jeśli użytkownik ponownie przewija - nie chcę, aby timer emitował wartości.

Obecnie robię tak:

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'); 
      }); 

Problemem jest to, że podczas przewijania - Widzę zarówno "throttle" I "tick" (mam tylko zobaczyć "przepustnicy")

myśleć o tym z innego POV. Praca zawsze musi zostać uruchomiona. Jeśli przewijam - ten zwężony przewijanie - powinien wywołać zadanie. Jeśli nie przewijam - timer powinien zacząć działać. (i zatrzymuje się, gdy użytkownik ponownie zacznie przewijać).

Pytanie:
Jak mogę uruchomić stoper po bezczynności nie przewijania?

PLNKR

+2

Oto jak zadać dobre pytanie na SO. +1 –

+0

Re [Twoja druga uwaga] (http://stackoverflow.com/questions/41522222/making-a-typing-timer-in-rxjs-tracking-time-spent-typing/41526650?noredirect=1#comment74109988_41526650) : Możesz rozwiązać ten problem, wykorzystując w tym celu 'exhaustMap' +' debounceTime', aby wykryć zwój.To co zrobiłem tutaj z 'switchMap' działa, ponieważ nic nie robimy podczas serii zdarzeń, a praca dzieje się, gdy strumień jest bezczynny. Odwrotnie, 'switchMap' wznowi zadanie (timer) za każdym razem, gdy zostanie wyemitowane nowe zdarzenie przewijania. – Dorus

Odpowiedz

2

zrobiłbym to tak:

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'); 
     }); 

używa operatora race() subskrybować jedynie obserwowalnym który emituje pierwszy który jest 1s interval lub zdarzenie przewijania. Zaraz potem chcę zacząć od nowa z innym interwałem, więc używam take(1).repeat().

Musiałem również zmienić obserwowalny scroll$ w gorący Obserwowalny, aby utrzymać throttleTime() w działaniu powtarzających się subskrypcji.

Zaktualizowana demo: https://plnkr.co/edit/sWzSm32uoOQ1hOKigo4s?p=preview

+0

Czy mogę zapytać, jaka jest różnica między 'publish(). Connect()' - tak jak zrobiłeś tutaj VS 'publish(). Refcount()' {który jest 'share()'} –

+0

@Royi 'connect() 'nie jest operatorem na wypowiedź (nie zwraca obserwowalnej). Jest to po prostu metoda na klasie 'ConnectableObservable', która zwraca' Subscription', której możesz użyć do "rozłączenia". Jest podobny do metody 'subscribe()', którą możesz połączyć z operatorem, ale zwraca również 'Subscription'. Oznacza to, że można go używać tylko na końcu łańcucha operatora. 'refCount()' z drugiej strony zwraca inną obserwowalną, dzięki czemu możesz połączyć ją z innymi operatorami. – martin

+0

Martin, Zrobiłeś to, co można zaobserwować, za pomocą połączenia. ale jeśli zmienię to na '.share()' (co jest również innym sposobem rozgrzania) - Następnie - podczas przewijania - wydaje się, że nie uwzględnia opóźnienia "przepustnicy". dlaczego ? https://plnkr.co/edit/jjWUxbk9fSItLT1U7uiq?p=preview –

3

Można użyć debounceTime wykryć okresy bez przewijania.

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) 

Innym problemem z kodem korzysta merge że zachowa oba źródła subskrybowanych, zamiast używać switchMap (rodzeństwo mergeMap), który będzie zapisać się do wewnętrznej obserwowalnym każdym nowym wydarzeniem jest emitowany, ale również wypisać poprzednie wewnętrzne źródło, jeśli inne wydarzenie jest emitowane ze źródła.

Re: "Kolejne POV" część pytania: Możesz zastąpić Rx.Observable.interval(1000) w switchMap z zadaniem. Przewijanie spowoduje anulowanie/anulowanie subskrypcji zadania (gdy zostanie wyemitowane empty), jeśli nie będzie już przewijania, zadanie zostanie uruchomione ponownie.

Live demo

+0

Byłoby wspaniale widząc te dwa plunkrs (2 podejść) –

+0

w kodzie Twoja odpowiedź jest, nie widzę żadnych emisji kiedy przewijać https://plnkr.co/edit/JX3QCjj6a9sBPM4fivZL?p=preview –

+0

:-) [I myślę, że napisałem to więcej niż jeden raz) (https://i.imgur.com/HfcsRt5.jpg) –

Powiązane problemy