暂停间隔rxjs [英] Pause an interval 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
推荐答案
我已经看到秒表问题经常出现,以至于我认为创建一个可观察的自定义秒表会很有趣.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
这将如何工作?我们的自定义可观察对象创建了一个流,该流输出秒表上的数字,并由一个单独的流控制(这里称为 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()};
});
}
使用中的秒表
以下是该可观察项被使用的示例.我通过一个主题来管理控制流,但是它可以很容易地被合并/映射的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
来控制秒表.
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屋!