暂停一个间隔 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
推荐答案
我看到秒表问题经常出现,我觉得创建一个自定义的 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屋!