暂停一个间隔 rxjs [英] Pause an interval rxjs

查看:24
本文介绍了暂停一个间隔 rxjs的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的秒表,使用 rxjs

I have a simple stopwatch, with using rxjs

问题是:无法获得如何暂停我的间隔流,然后继续它stackbiz

Problem is: can't get how to pause a stream of my interval, and then continue it stackbiz

推荐答案

我看到秒表问题经常出现,我觉得创建一个自定义的 stopWatch observable 会很有趣.RxJS 方式是通过切换进入和退出计时器/间隔来实现这一点.

I've seen stopwatch questions come up often enough that I figured it would be interesting to create a custom stopWatch observable. The RxJS way would be to implement this by switching into and out of timers/intervals.

另一种有趣的实现方式是使用 setTimeout 代替.setTimeout 实际上应该需要更少的内存,因为我们不依赖于可观察的设备来实现我们的计时目标

Another interesting way to implement this is by using setTimeout instead. setTimeout should actually require a bit less memory as we're not leaning on the observable apparatus to accomplish our timing goals

这将如何运作?我们的自定义 observable 创建了一个流,它输出秒表上的数字,并由一个单独的流控制(这里称为 control$).所以当 control$ 发出START"时,秒表启动,当它发出STOP"时,秒表停止,当它发出RESET"时,秒表停止.秒表将计数器设置为零.当 control$ 出错或完成时,秒表出错或完成.

How will this work? Our custom observable creates a stream that outputs the number on the stopwatch and is controlled by a separate stream (Here called control$). So 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.

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

    const endTicker$ = new Subject();

    const ticker = () => {
      return timer(0, interval).pipe(
        takeUntil(endTicker$),
        map(x => count++)
      )
    }
  
    return control$.pipe(
      tap({
        next: _ => {/*Do nothing*/},
        complete: () => {
          endTicker$.next();
          endTicker$.complete();
        },
        error: err => {
          endTicker$.next();
          endTicker$.complete();
        }
      }),
      filter(control => 
        control === "START" ||
        control === "STOP" ||
        control === "RESET"
      ),
      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;
      })
    );
  });
}

通过 setTimeout 实现

function createStopwatch(control: Observable<string>, interval = 1000): Observable<number> {
  return new Observable(observer => {
    let count: number = 0;
    let tickerId: number = null;

    const clearTicker = () => {
      if(tickerId != null){
          clearTimeout(tickerId);
          tickerId = null;
        }
    }
    const setTicker = () => {
      const recursiveTicker = () => {
        tickerId = setTimeout(() => {
          observer.next(count++);
          recursiveTicker();
        }, interval);
      }
      clearTicker();
      observer.next(count++);
      recursiveTicker();
    }

    control.subscribe({
      next: input => {
        if(input === "START" && tickerId == null){
          setTicker();
        }else if(input === "STOP"){
          clearTicker();
        }else if(input === "RESET"){
          count = 0;
          if(tickerId != null){
            setTicker();
          }
        }
      },
      complete: () => {
        clearTicker();
        observer.complete();
      },
      error: err => {
        clearTicker();
        observer.error(err);
      }
    });
  
    return {unsubscribe: () => clearTicker()};
  });
}

正在使用的秒表

这是使用此 observable 的示例.我通过一个主题管理控制流,但它可以很容易地被合并/映射 DOM 事件或类似的东西.

StopWatch in Use

Here is an example of this observable being used. I manage the control stream via a subject, but it could just as easily be merged/mapped DOM events or somesuch.

const control$ = new Subject<string>();
createStopwatch(control$, 250).subscribe(console.log);

// We send a new action to our control stream every 1 second
const actions = ["START", "STOP", "START", "RESET", "START"]

zip(from(actions), interval(1000)).pipe(
  map((x,y) => x),
  finalize(() => {
    // After 5 seconds, unsubscribe via the control
    // If our control finishes in any way (
    // completes, errors, or is unsubscribed), our
    // sopwatch reacts by doing the same.
    control$.complete();
  })
).subscribe(x => control$.next(x));

正在使用的秒表 #2

这用 setTimeout 而不是 interval 来控制秒表.

StopWatch in Use # 2

This controls the stopwatch with setTimeout instead of interval.

const control$ = new Subject<string>();
createStopwatch(control$, 250).subscribe(console.log);

// We send a new action to our control stream every 1 second
const actions = ["START", "STOP", "START", "RESET", "START"]

actions.forEach((val, index) => {
  setTimeout(() => {
    control$.next(val);
  },
  index * 1000);
})

// Unsubscribe via the control
setTimeout(() => {
  control$.complete();
}, actions.length * 1000);

这篇关于暂停一个间隔 rxjs的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆