Javascript 在Rxjs中,如何暂停数据流并从暂停的那一刻起继续?
我有一个数据流每10秒被长时间轮询一次。长pol可以暂停,也可以继续 问题是:它在继续时重新开始。我必须让它从暂停的那一刻起继续 因此,如果: 延迟(10000) 暂停在(7000) 然后,当我再次开始长时间轮询时,我的数据必须在(10000-7000)=3000 今天是第四天,我一直被这个问题困扰着,快要发疯了 我创造了这次闪电战Javascript 在Rxjs中,如何暂停数据流并从暂停的那一刻起继续?,javascript,angular,rxjs,reactive,rxjs6,Javascript,Angular,Rxjs,Reactive,Rxjs6,我有一个数据流每10秒被长时间轮询一次。长pol可以暂停,也可以继续 问题是:它在继续时重新开始。我必须让它从暂停的那一刻起继续 因此,如果: 延迟(10000) 暂停在(7000) 然后,当我再次开始长时间轮询时,我的数据必须在(10000-7000)=3000 今天是第四天,我一直被这个问题困扰着,快要发疯了 我创造了这次闪电战 创建了一个流和一个提取数据的计时器。当流和计时器停止时,设置与新延迟一起剩余的时间。但是,当我按下start时,它不会再等待3秒钟,它只是立即调用服务,这是我不想
创建了一个流和一个提取数据的计时器。当流和计时器停止时,设置与新延迟一起剩余的时间。但是,当我按下start时,它不会再等待3秒钟,它只是立即调用服务,这是我不想要的这是一个非常基本的实现,它依赖于
定时器
函数和take
、过滤器
和takeUntil
操作符
在我看来,这个解决方案并不太优雅。它取决于状态变量paused
和first
,并在订阅中的next
回调中具有递归触发器。还要注意的是,它目前没有进行任何错误处理。在这种情况下,轮询将完全停止
控制器
export const REFRESH\u INTERVAL=11;
@组件({…})
导出类AppComponent实现OnDestroy{
暂停$=新主题();
重置$=新主题();
已关闭$=新主题();
计数器=刷新间隔;
res:任何;
暂停=错误;
构造函数(私有freeApiService:freeApiService){}
恩戈尼尼特(){
this.init();
}
init(){
让第一个=真;
这是重置$
.烟斗(
开关映射(=>
计时器(0,1000)。管道(
拿(这个柜台)来说,
轻触(uz=>(this.paused=this.paused?false:this.paused)),
takeUntil(this.pause$),
过滤器(=>first | |--this.counter===0),
定稿(
()=>(this.paused=this.counter!=0?true:this.paused)
),
switchMap(=>this.freeApiService.getDummy())
)
),
takeUntil(此.closed$)
)
.订阅({
下一步:res=>{
第一个=假;
this.res=res;
this.counter=刷新间隔;
此.reset$.next();
},
错误:error=>console.log(“错误提示数据:”,错误)
});
}
恩贡德斯特罗(){
this.closed$.next();
}
}
模板
{{暂停?'Resume poll':'Pause poll'}
正在刷新:{{counter}
答复:
somePausableTimer$.pipe(
repeat(),
switchMap(() => of('polling time'))
)
{{res|json}
开始投票
我已经修改了您的我将结合使用
间隔
、过滤器
和扫描
操作符,检查频率设置为1s:
const pauserSubject=新行为主体(true);
常数s$=间隔(1000)。管道(
使用LatestFrom(pauserSubject),
过滤器(([InterValveValue,被允许]=>被允许),
扫描(acc=>acc+1,0),
点击(emissionNumber=>console.log('check-trument#',emissionNumber'on',new-Date().toTimeString()),
过滤器(emissionCount=>!(emissionCount%10)),
switchMapTo(of('request/response'))
);
在这种情况下,常规的间隔设置“节拍”,每1s检查一次暂停是否为真。取消暂停后,相应的过滤器
操作员允许继续操作。扫描
验证每10次检查(或每10秒)将导致http调用
对于您的场景:
你开始每10秒轮询一次
你在第三秒暂停一秒钟
计数器确保再进行7次检查(导致等待7秒)
http调用在第11秒进行(10次常规调用+1秒等待)
这归结为有一个“可暂停计时器”。完成后,您可以使用repeat
操作符在每次完成时重新运行它:
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)
);
});
}
如果您关心时间精度,下面是我对“pausable timer”(可暂停计时器)的看法-我认为它与javascript一样精确,但没有“每10毫秒检查一次暂停状态”等解决方案带来的性能损失:
你能把10秒分成10个更小的1秒延迟吗?看看同样的问题,就像秒表一样:-)这真是太棒了!非常感谢你!一个简短的问题;除了确保只订阅一次之外,这种方法还会导致内存泄漏吗?takeUntil(this.closed$)
理论上应该在关闭组件时关闭打开的订阅。所以我会说不,它不会导致任何内存泄漏。如果我对这段代码使用响应速度慢的api端点。它会重复请求,直到其中一个问题得到解决,而这正是我首先想要阻止的。我怎样才能解决这个问题?
const isActive$ = fromEvent(document, 'click').pipe(scan(acc => !acc, true)); // for example
pausableTimer(10000, isActive$).pipe(
repeat(),
switchMap(() => of('polling time'))
).subscribe();