每个服务器响应+延迟后轮询服务器

时间:2019-01-24 10:52:04

标签: angular rxjs ngrx rxjs6 ngrx-effects

我正在制作一个效果器,它将是轮询服务器。

我要实现的目标如下:

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动作,那么它可以正常工作-但是,如果我在请求发送之后发出了动作,那么在轮询停止之前,我还会收到一个后续的响应。

3 个答案:

答案 0 :(得分:2)

我认为您可以使用switchMaptimerdelay()来代替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));

https://stackblitz.com/edit/angular-mu3kp5

答案 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 })))
      );
    })
  );
}