简体   繁体   中英

RxJS Pause timer Observable

I have done a small timer, with 3 buttons:

start stop pause/resume (which I haven't done yet)

here is my code so far:

class StopwatchWidgetComponent {
      private readonly _start$: Subject<void> = new Subject();
      private readonly _stop$: Subject<void> = new Subject();
      private readonly _paused$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
      readonly counter$: Observable<number>;
    
      constructor() {
        this.counter$ = this._start$.pipe(
          startWith(0), // trigger emission at launch
          switchMap(() => timer(0, 1000).pipe(
            takeUntil(this._stop$)
          ))
        );

        // Subscribe done later
      }
    
      start(): void {
        this._start$.next();
      }
    
      stop(): void {
        this._stop$.next();
      }
    
      togglePause(): void {
        this._paused$.next(!this._paused$.getValue());
      }
}

However, I didn't manage to use the _paused$ subject properly so far. By looking at github, I found a few topics about this subject:

https://github.com/ReactiveX/rxjs/issues/1542

but I feel that in my case, I would need to get rid of the current timer observable, and trigger a new one starting from the value we stopped at when pausing (and thus having to store that value). Any other operator could help me out here to not have to do that?

An Implementation:

I create a timer with observables a while back. Perhaps it will give you some insight?

How does this work? The custom observable creates a stream that outputs the number on the stopwatch and is controlled by a separate stream (Here called control$ ).

When control$ emits "START", the stopWatch starts, when it emits "STOP", the stopwatch stops, and when it emits "RESET" the stopwatch sets the counter back to zero. When control$ errors or completes, the stopwatch errors or completes.

Implemented with switchMap and Timer

function createStopwatch(control$: Observable<string>, interval = 1000): Observable<number>{
  return defer(() => {
    let toggle: boolean = false;
    let count: number = 0;

    const ticker = timer(0, interval).pipe(
      map(x => count++)
    );
    const end$ = of("END");

    return concat(
      control$,
      end$
    ).pipe(
      catchError(_ => end$),
      filter(control => 
        control === "START" ||
        control === "STOP" ||
        control === "RESET" ||
        control === "END"
      ),
      switchMap(control => {
        if(control === "START" && !toggle){
          toggle = true;
          return ticker;
        }else if(control === "STOP" && toggle){
          toggle = false;
          return EMPTY;
        }else if(control === "RESET"){
          count = 0;
          if(toggle){
            return ticker;
          }
        }
        return EMPTY;
      })
    );
  });
}

Create a stopwatch as an object

If the control stream is going to be a subject, this is a good way to create the stopwatch.

function getStopWatch(interval: number = 1000): {
  control$: Subject<string>, 
  display$: Observable<number>
} {
  const control$ = new Subject<string>();
  return {
    control$,
    display$: createStopwatch(control$, interval)
  }
}

Stopwatch Object in Use:

const watch = getStopWatch();
watch.display$.subscribe(/*Numbers emitted here every interval once started by control$*/);
watch.control$.next("START");
watch.control$.next("STOP");
watch.control$.next("RESET");
// Completing the control cleans up everything
watch.control$.complete();

Create a stopwatch that gets a stream of DOM Events

createStopwatch(merge(
  fromEvent(startBtn, 'click').pipe(mapTo("START")),
  fromEvent(stopBtn, 'click').pipe(mapTo("STOP"))
  fromEvent(resetBtn, 'click').pipe(mapTo("RESET"))
)).subscribe(seconds => {
  secondsField.innerHTML  = seconds % 60;
  minuitesField.innerHTML = Math.floor(seconds / 60) % 60;
  hoursField.innerHTML    = Math.floor(seconds / 3600);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM