我有一个轮询用例,其中:
这就是我目前的实现方式:
this.trackSpoke$ = interval(5000)
.pipe(
timeout(250000),
startWith(0),
switchMap(() =>
this.sharedService.pollForAPropertyValue(
"newuser"
)
)
)
.subscribe(
(data: SpokeProperty) => {
this.CheckSpokeStatus(data);
},
error => {
this.trackSpoke$.unsubscribe();
this.createSpokeState.CdhResponseTimedOut();
}
);
private CheckSpokeStatus(data) {
if (data.PropertyValue === "5") {
this.trackSpoke$.unsubscribe();
//display success
} else {
//keep the polling going
}
}
但是,上述实现并没有超时。
需要做什么才能使其超时并且我能够实现所有提到的用例?
首先,使用
interval
进行 API 轮询是一种非常反模式,因为 interval
不会“等待”您的 http 请求完成 - 可能会触发多个请求(如果请求需要超过 5 秒才能完成)。
defer
与 repeatWhen
和 delay
一起使用(请参阅下面的代码)。
timeout
未触发,因为 interval
每 5 秒滴答一次,防止超时发生。 defer
/repeatWhen
组合也应该可以解决这个问题。
takeWhile
为您取消订阅 Observable,而不是手动取消订阅。
还不需要在错误处理程序中使用
this.trackSpoke$.unsubscribe();
,因为一旦发生错误,Observable 会自动取消订阅。
this.trackSpoke$ = defer(() => this.sharedService.pollForAPropertyValue("newuser"))
.pipe(
timeout(250000),
repeatWhen(notifications => notifications.delay(5000)),
takeWhile(data => this.CheckSpokeStatus(data)),
)
.subscribe(
error => {
this.createSpokeState.CdhResponseTimedOut();
}
);
private CheckSpokeStatus(data) {
return data.PropertyValue !== "5";
}
我有一个非常相似的用例。这是应该让您继续前进的代码...
from(fakeDelayedRequest()).pipe(
map((response) => {
if (isValidResponse(response)) {
return response;
} else {
throw `Not a valid response`;
}
}),
retry({
// getRetryDelayTimeOrThrow decides if we retry or not, depending on the error
// - returns an observable that triggers when the next request shall be sent
// - or throws the error which leads to exiting the retry loop
delay: getRetryDelayTimeOrThrow,
}),
timeout({
each: maxTimeout,
with: () => throwError(() => 'TIMEOUT'),
})
);
function getRetryDelayTimeOrThrow(e: any, retryCount: number) {
console.error(e);
if (repeatAfterError(e)) {
return timer(getPollInterval(retryCount));
} else {
throw e;
}
}