我正在制作一个效果器,它将是轮询服务器。
我要实现的目标如下:
1)将GET请求发送到服务器
2)收到响应后,等待3秒钟
3)发送相同的GET请求
4)收到响应后,等待3秒钟
5)发送相同的GET请求
...等等。
我现在拥有的代码无法正常工作,因为它每3秒轮询一次服务器,无论是否收到响应:
@Effect()
pollEntries$ = this.actions$.pipe(
ofType(SubnetBrowserPageActions.SubnetBrowserPageActionTypes.StartPollingSubnetEntries),
switchMap(() => {
return timer(0, 3000);
}),
takeUntil(this.actions$.pipe(ofType(SubnetBrowserPageActions.SubnetBrowserPageActionTypes.StopPollingSubnetEntries))),
switchMap(() => {
return this.subnetBrowserService.getSubnetEntries();
}),
map((entries) => {
return new SubnetBrowserApiActions.LoadEntriesSucces({ entries });
}),
catchError((error) => {
return of(new SubnetBrowserApiActions.LoadEntriesFailure({ error }));
}),
);
我正在努力解决的另一件事是如何停止轮询。如果我在将请求发送到服务器之前发出了StopPollingSubnetEntries
动作,那么它可以正常工作-但是,如果我在请求发送之后发出了动作,那么在轮询停止之前,我还会收到一个后续的响应。
答案 0 :(得分:2)
我认为您可以使用switchMap
,timer
和delay()
来代替take(1)
和repeat()
,而不是:
const stop$ = this.actions$.pipe(ofType(SubnetBrowserPageActions.SubnetBrowserPageActionTypes.StopPollingSubnetEntries));
@Effect()
pollEntries$ = this.actions$.pipe(
ofType(SubnetBrowserPageActions.SubnetBrowserPageActionTypes.StartPollingSubnetEntries),
switchMap(() => this.subnetBrowserService.getSubnetEntries().pipe(
catchError(...),
delay(3000),
take(1),
repeat(),
takeUntil(stop$),
)),
);
答案 1 :(得分:1)
您可以使用expand
连续映射到下一个http请求并预先添加delay
。
const stopPolling$ = this.actions$.pipe(
ofType(SubnetBrowserPageActions.SubnetBrowserPageActionTypes.StopPollingSubnetEntries)
);
const httpRequest$ = this.subnetBrowserService.getSubnetEntries().pipe(
map(entries => new SubnetBrowserApiActions.LoadEntriesSucces({ entries })),
catchError(error => of(new SubnetBrowserApiActions.LoadEntriesFailure({ error })))
)
const pollEntries$ = this.httpRequest$.pipe(
expand(_ => of(1).pipe(
delay(3000),
mergeMap(_ => this.httpRequest$),
)),
takeUntil(this.stopPolling$)
);
要开始轮询,您必须订阅pollEntries$
。
startPolling() {
this.pollEntries$.subscribe(entries => console.log(entries));
}
或者在您的操作发出时映射到pollEntries
。
const pollEntriesOnAction$ = this.actions$.pipe(
ofType(SubnetBrowserPageActions.SubnetBrowserPageActionTypes.StartPollingSubnetEntries),
switchMap(() => this.pollEntries$)
);
this.pollEntriesOnAction$.subscribe(entries => console.log(entries));
答案 2 :(得分:0)
我写了一篇有关该主题的博客文章-https://bbonczek.github.io/jekyll/update/2018/03/01/polling-with-ngrx.html。
我决定创建一些小效果,以便在协同工作时可以轮询服务器。代码:
@Injectable()
export class SubnetEffects {
constructor(
private actions$: Actions<SubnetActions.SubnetActionsUnion>,
private http: HttpClient
) {}
private isPollingActive = false;
@Effect()
startPolling$ = this.actions$.pipe(
ofType(SubnetActions.SubnetActionTypes.StartPollingSubnetDevices),
map(() => this.isPollingActive = false), // switch flag to true
switchMap(() => {
return this.http.get<SubnetEntry>('http://localhost:5000/api/subnet').pipe(
switchMap(entries => new SubnetActions.GetSubnetDevicesSucceded({ entries })),
catchError(error => of(new SubnetActions.GetSubnetDevicesFailed({ error })))
),
}),
);
@Effect()
stopPolling$ = this.actions$.pipe(
ofType(SubnetActions.SubnetActionTypes.StopPollingSubnetDevices),
map(() => this.isPollingActive = false) // switch flag to false
);
@Effect()
continuePolling$ = this.actions$.pipe(
ofType(
SubnetActions.SubnetActionTypes.GetSubnetDevicesSucceded,
SubnetActions.SubnetActionTypes.GetSubnetDevicesFailed
),
takeWhile(() => this.isPollingActive), // do this only as long as flag is set to true
switchMap(() => {
return this.http.get<SubnetEntry>('http://localhost:5000/api/subnet').pipe(
delay(5000),
switchMap(entries => new SubnetActions.GetSubnetDevicesSucceded({ entries })),
catchError(error => of(new SubnetActions.GetSubnetDevicesFailed({ error })))
);
})
);
}