Angular 轮询服务,直到在特定时间段后收到响应或超时
要求 呼叫服务 如果该服务返回数据,则将数据设置为变量。功能结束 如果该服务返回data=null,则每隔20秒重复调用该服务,直到它返回data=“列表或对象”或调用该服务2分钟并停止 我尝试的 需要每隔20秒轮询此服务getUrlById(id),直到我在this.url中得到响应或在6分钟后超时 尝试了以下解决方案,但未按预期工作Angular 轮询服务,直到在特定时间段后收到响应或超时,angular,typescript,rxjs,angular8,Angular,Typescript,Rxjs,Angular8,要求 呼叫服务 如果该服务返回数据,则将数据设置为变量。功能结束 如果该服务返回data=null,则每隔20秒重复调用该服务,直到它返回data=“列表或对象”或调用该服务2分钟并停止 我尝试的 需要每隔20秒轮询此服务getUrlById(id),直到我在this.url中得到响应或在6分钟后超时 尝试了以下解决方案,但未按预期工作 pollUrl(id) { interval(2000).pipe( timeout(600000), takeWhile(()
pollUrl(id) {
interval(2000).pipe(
timeout(600000),
takeWhile(() => this.url)
).subscribe(i => {
this.service.getUrlById(id).subscribe(res =>{
if(res && res["result"]){
this.url = res["result"];
}
})
})
}
从我尝试的评论中
在此处调用了虚拟服务
这里,虚拟服务返回data=null。所以根据要求,我需要每隔20秒打一次电话,直到2分钟。这是行不通的
没有必要使用此代码,我希望达到要求。可以有不同的方法。只需使用
find
操作符(找到通过某个测试的第一个值并发出该值),这样getUrlById
返回的可观察值在响应后立即完成。结果定义如下所示:
interval(2000)
.pipe(
exhaustMap(() => this.service.getUrlById(id)), // <== switch subscription to `getUrlById`
find(x => x && x.result && x.result.length > 0),
timeout(6 * 60 * 1000)
)
.subscribe(i => { })
您是否尝试过使用RetryWhen操作符
比如:(链接:)
首先,在这种情况下,timeout
操作符是多余的。如果源在600000
ms内没有发射,则应该抛出错误,但这永远不会发生,因为源将每隔2000
ms发射一次
考虑到这一点,我的方法如下:
间隔(2000)。管道(
switchMap(id=>this.service.getUrlById(id)),
过滤器(res&&res[“结果”]),
//如果我们得到响应->停止轮询
第一个(),
//如果我们在600000毫秒->停止轮询中没有得到响应
takeUntil(计时器(600000)),
)
它以前不起作用,可能是因为takeWhile(()=>this.url)
是在this.url
被填充之前到达的,这意味着当调用takeWhile
的回调函数时,this.url
是未定义的(任何虚假值),因此,整个流应该已经完成。每当出现轮询时,通常需要使用expand
操作符,原因之一是它可以排除请求占用的时间超过您的轮询周期,并且您会同时收到两个请求的情况。差不多
const api$ = this.service.getUrlById(id);
api$.pipe(
expand(x => x && x.result && x.result.length > 0 ? EMPTY : api$.pipe(delay(2000))),
last(), // get the result
timeout(6 * 60 * 1000)
)
.subscribe(i => { })
of(undefined).pipe(
expand((result) =>
result === undefined
? this.service.getUrlById(id).pipe(
map((data) => data?.result),
switchMap((result) =>
result !== undefined
? of(result)
: of(undefined).pipe(delay(20000)),
),
)
: EMPTY,
),
filter((result) => result !== undefined),
timeout(600000),
);
查找(x=>x?.result)-此行抛出以下错误。类型“Object”上不存在属性“result”。运行ng serve时ts(2339)查找((x:any)=>x?.result)错误。错误TS1109:应为表达式。src/app/register.component.ts(420,31):错误TS1005:“:”应为。i「wdm」:编译失败。请参阅我的更新,事实上getUrlById
应返回实际类型,而不是返回类型object
find((x:any)=>x?.result)。这是来自更新。为什么这行有错误。“:”预期编译失败。我怀疑链接运算符在angular 8中不起作用(不确定),请查看我的更新。我可以在某个时候将值res[“result”]保存到this.url变量吗?@user630209是的,只需在过滤器()之后添加一个点击(res=>this.url=res[“result”])
为什么要先使用文件管理器
+而查找
可用?@RafiHenig感谢您指出,它们可以互换使用,尽管每个都可以扩展到其他用例。例如,使用find
可以选择仅返回值上调用的cb返回true的索引first
可以有默认值,而find没有默认值。“在这种情况下,超时运算符是多余的。如果源在600000毫秒内没有发射,则应该抛出错误,但这永远不会发生,因为源将每2000毫秒发射一次。
”这不是真的,因为filter/find将过滤不需要的值。@user630209
请参阅我的更新如果响应数据为空,服务需要再次调用。这不起作用。状态:429,状态文本:“太多请求”由于出现错误,可观察到的停止
of(undefined).pipe(
expand((result) =>
result === undefined
? this.service.getUrlById(id).pipe(
map((data) => data?.result),
switchMap((result) =>
result !== undefined
? of(result)
: of(undefined).pipe(delay(20000)),
),
)
: EMPTY,
),
filter((result) => result !== undefined),
timeout(600000),
);