Опрос сервера после каждого ответа сервера + задержка - PullRequest
0 голосов
/ 24 января 2019

Я работаю над эффектом, который будет сервером опроса.

То, чего я хочу добиться, это:

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 голосов
/ 24 января 2019

Вы можете использовать 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

0 голосов
/ 01 марта 2019

Я написал пост в блоге на эту тему - 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 })))
      );
    })
  );
}
0 голосов
/ 24 января 2019

Я думаю, что вы были близки только вместо 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$),
  )),
);
...