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

Polling server after each server response + delay

我正在制作一种效果,它将成为轮询服务器。

我想达到的效果如下:

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

我认为你很接近,而不是 switchMaptimer 你可以使用 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$),
  )),
);

您可以使用expand连续映射到下一个http请求并预先添加一个timer

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(_ => timer(3000).pipe(
    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-cdtwoc?file=app/app.component.ts

我写了一篇关于这个主题的博客 post - 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 })))
      );
    })
  );
}