【问题标题】:Polling server after each server response + delay每次服务器响应+延迟后轮询服务器
【发布时间】:2023-04-10 00:57:01
【问题描述】:

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

我想要达到的效果如下:

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

【问题讨论】:

标签: angular rxjs ngrx rxjs6 ngrx-effects


【解决方案1】:

您可以使用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

【讨论】:

  • 不幸的是,它似乎不起作用 - getSubnetEntries() 只发送一次,然后一遍又一遍地重复相同的响应。
  • 感谢您的通知。我使用延迟的 Observable 而不是 httpRequest 测试了代码,它似乎可以工作。我可能会在这里修复我的代码,但同时也发现了另一个关于您的问题的 SO 问题和博客。我会为您的问题添加评论。
  • @bartosz.baczek 你确定我的代码不起作用吗?我已经在我的答案中添加了一个 stackblitz,我现在使用真正的 http 请求,它似乎可以工作。请尝试一下。
【解决方案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$),
  )),
);

【讨论】:

  • 似乎您的代码仍在使用 switchmap。你的意思是在那里使用 concatMap 吗?
  • 我的意思是第二个switchMap。但是,是的,我最后不需要concatMap
  • 您的代码似乎有问题 - this.subnetBrowserService.getSubnetEntries() 仅调用一次,并且仅重复第二个管道中的代码。
  • 我认为这正是您想要的。
  • take(1) 是完成链所必需的,因此repeat() 可以重新订阅并重新开始。是的,它确实在重新发出响应之前增加了延迟。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2018-05-19
    • 2011-09-26
    • 2018-08-09
    • 2013-01-02
    • 2012-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-25
    相关资源
    最近更新 更多