Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/453.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在Rxjs中,如何暂停数据流并从暂停的那一刻起继续?_Javascript_Angular_Rxjs_Reactive_Rxjs6 - Fatal编程技术网

Javascript 在Rxjs中,如何暂停数据流并从暂停的那一刻起继续?

Javascript 在Rxjs中,如何暂停数据流并从暂停的那一刻起继续?,javascript,angular,rxjs,reactive,rxjs6,Javascript,Angular,Rxjs,Reactive,Rxjs6,我有一个数据流每10秒被长时间轮询一次。长pol可以暂停,也可以继续 问题是:它在继续时重新开始。我必须让它从暂停的那一刻起继续 因此,如果: 延迟(10000) 暂停在(7000) 然后,当我再次开始长时间轮询时,我的数据必须在(10000-7000)=3000 今天是第四天,我一直被这个问题困扰着,快要发疯了 我创造了这次闪电战 创建了一个流和一个提取数据的计时器。当流和计时器停止时,设置与新延迟一起剩余的时间。但是,当我按下start时,它不会再等待3秒钟,它只是立即调用服务,这是我不想

我有一个数据流每10秒被长时间轮询一次。长pol可以暂停,也可以继续

问题是:它在继续时重新开始。我必须让它从暂停的那一刻起继续

因此,如果:

延迟(10000)

暂停在(7000)

然后,当我再次开始长时间轮询时,我的数据必须在(10000-7000)=3000

今天是第四天,我一直被这个问题困扰着,快要发疯了

我创造了这次闪电战


创建了一个流和一个提取数据的计时器。当流和计时器停止时,设置与新延迟一起剩余的时间。但是,当我按下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();