这归结为有一个“可暂停计时器”。完成后,您只需使用 repeat 运算符在它完成时重新运行它:
somePausableTimer$.pipe(
repeat(),
switchMap(() => of('polling time'))
)
如果您关心时间精度,这是我对“可暂停计时器”的看法 - 我认为它与 javascript 一样精确,但没有“每 10 次检查暂停状态”等解决方案带来的性能损失毫秒”:
import {delay, distinctUntilChanged, filter, map, mapTo, pairwise, repeat,
scan, startWith, switchMap, take, withLatestFrom} from 'rxjs/operators';
import {defer, fromEvent, NEVER, Observable, of} from 'rxjs';
function pausableTimer(timerSpan: number, isActive$: Observable<boolean>): Observable<boolean> {
const activeState$ = isActive$.pipe(
distinctUntilChanged(),
startWith(true, true),
map(isActive => ({
isActive,
at: Date.now()
}))
);
const pauseSpans$ = activeState$.pipe(
pairwise(),
filter(([,curr]) => curr.isActive),
map(([prev, curr]) => curr.at - prev.at)
);
const accumulatedPauseSpan$ = pauseSpans$.pipe(
scan((acc, curr) => acc += curr, 0)
);
return defer(() => {
const startTime = Date.now();
const originalEndTime = startTime + timerSpan;
return activeState$.pipe(
withLatestFrom(accumulatedPauseSpan$),
switchMap(([activeState, accPause]) => {
if (activeState.isActive) {
return of(true).pipe(
delay(originalEndTime - Date.now() + accPause)
);
}
else {
return NEVER;
}
}),
take(1)
);
});
}
该函数接受以毫秒为单位的timerSpan(在您的情况下为10000)和一个isActive$ observable,它发出true/false 用于恢复/暂停。所以把它放在一起:
const isActive$ = fromEvent(document, 'click').pipe(scan(acc => !acc, true)); // for example
pausableTimer(10000, isActive$).pipe(
repeat(),
switchMap(() => of('polling time'))
).subscribe();