我创建了一个类,该类设置了可观察到的可暂停的rxjs:
export class RepeatingServiceCall<T> {
private paused = false;
private observable: Observable<T>;
constructor(serviceCall: () => Observable<T>, delay: number) {
this.observable = interval(delay).pipe(flatMap(() => (!this.paused ? serviceCall() : NEVER)));
}
setPaused(paused: boolean) {
this.paused = paused;
}
getObservable() {
return observable;
}
}
这似乎工作正常,但是我要解决的问题是我希望计时器在不暂停时重置。因此,假设间隔时间是上一次发出间隔setPaused(false)
被调用之后的10秒和5秒。在这种情况下,我希望它立即发出,然后重新启动计时器。这样添加起来会很容易吗?
答案 0 :(得分:3)
If you use timer
instead of interval
, and set the initial delay to 0
, then your interval will fire immediately.
You can use takeUntil
operator to prevent the interval to run always, and repeatWhen
operator to restart it whenever you want:
import { Observable, Subject, timer } from 'rxjs';
import { repeatWhen, switchMap, takeUntil } from 'rxjs/operators';
export class RepeatingServiceCall<T> {
readonly observable$: Observable<T>;
private readonly _stop = new Subject<void>();
private readonly _start = new Subject<void>();
constructor(serviceCall: () => Observable<T>, delay: number) {
this.observable$ = timer(0, delay)
.pipe(
switchMap(() => serviceCall()),
takeUntil(this._stop),
repeatWhen(() => this._start)
);
}
start(): void {
this._start.next();
}
stop(): void {
this._stop.next();
}
}
Here is a working StackBlitz example.
P.S.: Getters and setters are working different in typescript. So you do not need classic getter concept, you can just make the attribute public
and readonly
.
答案 1 :(得分:1)
您可以通过以下代码段实现您描述的行为:
const delay = 1000;
const playing = new BehaviorSubject(false);
const observable = playing.pipe(
switchMap(e => !!e ? interval(delay).pipe(startWith('start')) : never())
);
observable.subscribe(e => console.log(e));
// play:
playing.next(true);
// pause:
playing.next(false);
playing
观察对象发出true
时,switchMap
运算符将返回一个新的interval
观察对象。startWith
运算符立即发出事件。true
初始化BehaviorSubject。答案 2 :(得分:0)
You can abandon the old timer on start and start a new one on start.
const { interval, Subject, fromEvent } = rxjs;
const { takeUntil } = rxjs.operators;
let timer$;
const pause = new Subject();
const obs$ = new Subject();
obs$.subscribe(_ => { console.log('Timer fired') });
function start() {
timer$ = interval(1000);
timer$.pipe(takeUntil(pause)).subscribe(_ => { obs$.next(); });
}
function stop() {
pause.next();
timer$ = undefined;
}
fromEvent(document.getElementById('toggle'), 'click').subscribe(() => {
if (timer$) {
stop();
} else {
start();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>
<button id="toggle">Start/Stop</button>
答案 3 :(得分:0)
Yet another approach with a switchMap
:
const { fromEvent, timer } = rxjs;
const { takeUntil, switchMap, startWith } = rxjs.operators;
const start$ = fromEvent(document.getElementById('start'), 'click');
const stop$ = fromEvent(document.getElementById('stop'), 'click');
start$.pipe(
startWith(void 0), // trigger emission at launch
switchMap(() => timer(0, 1000).pipe(
takeUntil(stop$)
))
).subscribe(console.log);
<script src="https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js"></script>
<button id="start">start</button>
<button id="stop">stop</button>
And a simpler one, that merge
s start and stop Observables to switch off them:
const { fromEvent, merge, timer, NEVER } = rxjs;
const { distinctUntilChanged, switchMap, mapTo, startWith } = rxjs.operators;
const start$ = fromEvent(document.getElementById('start'), 'click');
const stop$ = fromEvent(document.getElementById('stop'), 'click');
merge(
start$.pipe(mapTo(true), startWith(true)),
stop$.pipe(mapTo(false))
).pipe(
distinctUntilChanged(),
switchMap(paused => paused ? timer(0, 1000) : NEVER)
)
.subscribe(console.log);
<script src="https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js"></script>
<button id="start">start</button>
<button id="stop">stop</button>
And another, even wierder approach, using repeat()
:
const { fromEvent, timer } = rxjs;
const { take, concatMap, takeUntil, repeat } = rxjs.operators;
const start$ = fromEvent(document.getElementById('start'), 'click');
const stop$ = fromEvent(document.getElementById('stop'), 'click');
start$.pipe(
take(1),
concatMap(()=>timer(0, 1000)),
takeUntil(stop$),
repeat()
).subscribe(console.log);
<script src="https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js"></script>
<button id="start">start</button>
<button id="stop">stop</button>
Just wanted to join this party :)
答案 4 :(得分:0)
检查此代码
/**
* it is a simple timer created by via rxjs
* @author KentWood
* email minzojian@hotmail.com
*/
function rxjs_timer(interval, times, tickerCallback, doneCallback, startDelay) {
this.pause = function () {
this.paused = true;
}
this.resume = function () {
this.paused = false;
}
this.stop = function () {
if (this.obs) {
this.obs.complete();
this.obs.unsubscribe();
}
this.obs = null;
}
this.start = function (interval, times, tickerCallback, doneCallback, startDelay) {
this.startDelay = startDelay || 0;
this.interval = interval || 1000;
this.times = times || Number.MAX_VALUE;
this.currentTime = 0;
this.stop();
rxjs.Observable.create((obs) => {
this.obs = obs;
let p = rxjs.timer(this.startDelay, this.interval).pipe(
rxjs.operators.filter(() => (!this.paused)),
rxjs.operators.tap(() => {
if (this.currentTime++ >= this.times) {
this.stop();
}
}),
rxjs.operators.map(()=>(this.currentTime-1))
);
let sub = p.subscribe(val => obs.next(val), err => obs.error(err), () => obs
.complete());
return sub;
}).subscribe(tickerCallback, null, doneCallback);
}
this.start(interval, times, tickerCallback, doneCallback, startDelay);
}
/////////////test/////////////
var mytimer = new rxjs_timer(
1000/*interval*/,
10 /*times*/,
(v) => {logout(`time:${v}`)}/*tick callback*/,
() => {logout('done')}/*complete callback*/,
2000/*start delay*/);
//call mytimer.pause()
//call mytimer.resume()
//call mytimer.stop()
function logout(str){
document.getElementById('log').insertAdjacentHTML( 'afterbegin',`<p>${str}</p>`)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.1/rxjs.umd.js"></script>
<button onclick="mytimer.pause()"> pause</button>
<button onclick="mytimer.resume()"> resume</button>
<button onclick="mytimer.stop()"> stop</button>
<div id='log'></div>