Angular 暂停/恢复可观察到的计时器

Angular 暂停/恢复可观察到的计时器,angular,angular6,rxjs6,Angular,Angular6,Rxjs6,我正在用angular/rxjs6构建一个简单的秒表,我可以启动计时器,但不能暂停/恢复计时器 source: Observable<number>; subscribe: Subscription; start() { this.source = timer(0, 1000); this.subscribe = this.source .subscribe(number => { this.toSeconds = nu

我正在用angular/rxjs6构建一个简单的秒表,我可以启动计时器,但不能暂停/恢复计时器

  source: Observable<number>;
  subscribe: Subscription;

  start() {
    this.source = timer(0, 1000);
    this.subscribe = this.source
      .subscribe(number => {
        this.toSeconds = number % 60;
        this.toMinutes = Math.floor(number / 60);
        this.toHours = Math.floor(number / (60 * 60));

        this.seconds = (this.toSeconds < 10 ? '0' : '') + this.toSeconds;
        this.minutes = (this.toMinutes < 10 ? '0' : '') + this.toMinutes;
        this.hours = (this.toHours < 10 ? '0' : '') + this.toHours;
    });
  }

  pause() {
    this.subscribe.unsubscribe(); // not working
  }
来源:可见;
认购:认购;
开始(){
this.source=计时器(0,1000);
this.subscribe=this.source
.订阅(号码=>{
this.toSeconds=数字%60;
this.toMinutes=数学楼层(数字/60);
this.toHours=数学楼层(编号/(60*60));
this.seconds=(this.toSeconds<10?'0':'')+this.toSeconds;
this.minutes=(this.toMinutes<10?'0':'')+this.toMinutes;
this.hours=(this.toHours<10?'0':'')+this.toHours;
});
}
暂停(){
this.subscribe.unsubscribe();//不工作
}
在做了大量的搜索之后,我发现我应该使用
switchMap
操作符来实现这一点,但我对rxjs还不熟悉,不知道如何正确地进行操作


任何帮助都将不胜感激。

我从未使用过
timer()
函数,但您可以做的是设置一个这样的标志

  source: Observable<number>;
  subscribe: Subscription;
  timerPaused: boolean = false;


  start() {
    this.seconds = 0;
    this.minutes = 0;
    this.hours = 0;
    this.time = 0;

    this.source = timer(0, 1000);
    this.subscribe = this.source
      .subscribe(number => {
        if(!this.timerPaused) {
          this.toSeconds = this.time % 60;
          this.toMinutes = Math.floor(this.time / 60);
          this.toHours = Math.floor(this.time / (60 * 60));

          this.seconds = (this.toSeconds < 10 ? '0' : '') + this.toSeconds;
          this.minutes = (this.toMinutes < 10 ? '0' : '') + Math.floor(number / 60);
          this.hours = (this.toHours < 10 ? '0' : '') + Math.floor(number / (60 * 60));
          this.time += 1000
        }
      });
  }

  onPause() {
    this.timerPaused = true;
  }

  onResume() {
    this.timerPaused = false;
  }

  ngOnDestroy() {
    this.subscribe.unsubscribe();
  }
来源:可见;
认购:认购;
timerPaused:boolean=false;
开始(){
这1.5秒=0;
这1.5分钟=0;
这1.4小时=0;
这个时间=0;
this.source=计时器(0,1000);
this.subscribe=this.source
.订阅(号码=>{
如果(!this.timerPaused){
this.toSeconds=this.time%60;
this.toMinutes=Math.floor(this.time/60);
this.toHours=数学地板(this.time/(60*60));
this.seconds=(this.toSeconds<10?'0':'')+this.toSeconds;
this.minutes=(this.tomminutes<10?'0':'')+数学楼层(数字/60);
this.hours=(this.toHours<10?'0':'')+数学楼层(数字/(60*60));
这个时间+=1000
}
});
}
onPause(){
this.timerPaused=true;
}
onResume(){
this.timerPaused=false;
}
恩贡德斯特罗(){
this.subscribe.unsubscribe();
}

这是一个使用rxjs 6的node.js代码段。除非按下
p
,否则将发出计时器事件。再次按下时,排放继续(
ctrl-c
将退出)

在内部,当暂停器发出
false
时,实际上启动了一个新的计时器。因此,我们在(
concat
)用
false
发射来预先设置暂停器,以启动第一个计时器。2
scan
操作员管理链的状态(暂停切换器+计数器)

import { timer, concat, NEVER, of, fromEvent } from 'rxjs';
import { scan, tap, filter, switchMap } from 'rxjs/operators';
import { emitKeypressEvents } from 'readline';

process.stdin.setRawMode(true);
emitKeypressEvents(process.stdin);

const keypresses$ = fromEvent(process.stdin, 'keypress', (_, key) => key);
const pauser$ = keypresses$.pipe(
  tap(key => {
    if (key && key.ctrl && key.name == 'c') {
      process.exit(0);
    }
  }),
  filter(key => key.name === 'p'),
  scan(acc => !acc, false),
);

const starter$ = of(false);
concat(starter$, pauser$)
  .pipe(
    switchMap(stopped => (stopped ? NEVER : timer(0, 1000))),
    scan(acc => acc + 1, 0),
  )
  .subscribe(console.log);

我今天也遇到了同样的问题(用Angular实现俄罗斯方块克隆时)。以下是我的结论:

import { Subject, timer } from 'rxjs';

export class Timer {
  private timeElapsed = 0;
  private timer = null;
  private subscription = null;

  private readonly step: number;

  update = new Subject<number>();

  constructor(step: number) {
    this.timeElapsed = 0;
    this.step = step;
  }

  start() {
    this.timer = timer(this.step, this.step);
    this.subscription = this.timer.subscribe(() => {
      this.timeElapsed = this.timeElapsed + this.step;
      this.update.next(this.timeElapsed);
    });
  }

  pause() {
    if (this.timer) {
      this.subscription.unsubscribe();
      this.timer = null;
    } else {
      this.start();
    }
  }

  stop() {
    if (this.timer) {
      this.subscription.unsubscribe();
      this.timer = null;
    }
  }
}

注意:我是Angular/RxJS新手,所以我不确定上面的代码是否好。但它可以工作。

这不是暂停计时器本身,而是暂停我使用的局部变量。如果我将计时器暂停15秒,然后等待5秒再重新启动,它将以20秒而不是16秒开始。因为计时器本身仍在运行,那么添加一个时间变量,比如我刚才更新的时间变量,怎么样?我看到的所有示例都使用
timer()
.setInterval()
这样做。我不知道如何真正暂停订阅。实际上,我找到了一种使用
switchMap
操作符的方法,但我无法在这里应用它。如果我找不到暂停/恢复可观察对象的方法,我将使用setInterval。非常感谢@rhavelkathan这个答案似乎正是我想要的。然而,我试图在和的帮助下以角度实现它,但没有运气。如果你能用我在问题中发布的代码帮助我实现它,那就太好了。谢谢你需要让你的“暂停/取消暂停”动作成为一个可观察的动作(现在它们似乎是被调用的函数,我想点击一个按钮),然后你可以
切换映射
暂停/取消暂停
动作到计时器,这就是想法。当您有一个
pauser$
可观察时,您应该能够使用上面的代码。
  init() {
    this.timer = new Timer(50);
    this.timer.start();
    this.timer.update.subscribe(timeElapsed => {
      if (timeElapsed % 1000 === 0) {
        this.step(); // step() runs one game iteration
      }
    });
  }

  togglePause() {
    this.timer.pause();
  }