简体   繁体   English

RxJS 暂停定时器 Observable

[英]RxJS Pause timer Observable

I have done a small timer, with 3 buttons:我做了一个小计时器,有3个按钮:

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.但是,到目前为止,我还没有设法正确使用_paused$主题。 By looking at github, I found a few topics about this subject:通过查看 github,我发现了一些关于这个主题的主题:

https://github.com/ReactiveX/rxjs/issues/1542 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.不久前,我创建了一个带有 observables 的计时器。 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$ ).自定义的 observable 创建了一个 stream 输出秒表上的数字,并由单独的 stream 控制(这里称为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.control$发出“START”时,秒表启动,当它发出“STOP”时,秒表停止,当它发出“RESET”时,秒表将计数器设置回零。 When control$ errors or completes, the stopwatch errors or completes.control$出错或完成时,秒表出错或完成。

Implemented with switchMap and Timer用 switchMap 和 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创建一个秒表作为 object

If the control stream is going to be a subject, this is a good way to create the stopwatch.如果控件 stream 将成为主题,这是创建秒表的好方法。

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:秒表 Object 使用中:

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创建一个获取 DOM 事件的 stream 的秒表

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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