【问题标题】:RxJS Observable with Subject, polling via timer and combineLatest does not fire带有 Subject 的 RxJS Observable,通过计时器和 combineLatest 轮询不会触发
【发布时间】:2017-07-11 16:56:12
【问题描述】:

我编写了一个函数来对一个也可以进行分页的 API 进行轮询。为此,分页是使用 Subject Observable 完成的,轮询是使用 timer 方法完成的(我也尝试了间隔,结果相同)。

这是我的代码:

  getItems(pagination: Subject<Pagination>): Observable<ListResult<Item>> {
    let params: URLSearchParams = new URLSearchParams();

    return Observable
      .timer(0, 5000)
      .combineLatest(
        pagination,
        (timer, pagination) => pagination
      )
      .startWith({offset: 0, limit: 3})
      .switchMap(pagination => {
        params.set('skip', pagination.offset.toString());
        params.set('limit', pagination.limit.toString());
        return this.authHttp.get(`${environment.apiBase}/items`, {search: params})
      })
      .map(response => response.json() as ListResult<Item>)
      .catch(this.handleError);
  }

预期的行为是: HTTP 请求每 5 秒触发一次,并且在用户更改页面时触发。

会发生这种情况: 第一个 HTTP 请求被触发,但没有其他请求被发送到服务器直到使用分页。 第一次使用分页后,轮询也开始工作。

这是我第一次使用 Observables,所以我很确定我错过了一些东西,但我看不出它可能是什么。

我也尝试过这种方法(也许它缺少 startWith 中的计时器),但它没有改变任何东西。

[...]
  .combineLatest(
    pagination
  )
  .startWith([0, {offset: 0, limit: 3}])
[...]

【问题讨论】:

  • combineLatest 仅在两个可观察对象都发出一次 play with the RxJS marbles to see 时才有效。我在想也许你的startsWith 需要在与计时器结合之前应用于分页。
  • 这就是马丁在他的解决方案中所建议的(你们都是对的)。我知道 combineLatest 确实会等待所有的 observables,但我不知何故认为 startWith 会自动启动两个 Observables。我错了;)

标签: angular typescript rxjs polling rxjs5


【解决方案1】:

combineLatest() 运算符要求所有源 Observable 至少发出一项。

您的演示只发出一个请求,因为您使用的是.startWith()combineLatest() 从不发射,因为 paginationSubject,它可能从不发射任何项目。

所以一种选择是移动.startWith()

.combineLatest(
  pagination.startWith({offset: 0, limit: 3}),
  (timer, pagination) => pagination
)

但这可能对您没有多大帮助,因为您忽略了来自timer() 的所有项目,而您只使用了pagination。因此,也许您可​​以只使用merge() 从其中一个来源刷新列表。然后timer() 独立增加偏移量。

Observable
  .timer(0, 1000)
  .map(i => { return {offset: i*3, limit: 3}})
  .merge(pagination.startWith({offset: 0, limit: 3}))
  .switchMap(pagination => {
    return Observable.of(pagination).delay(200)
  })
  .subscribe(val => console.log(val));

【讨论】:

  • 您的第一个答案有效!我刚刚将 startWith 移动到分页 Subject Observable 并且它起作用了。当我在我的解决方案中使用 startWith 时,计时器实际上工作了,但是分页 Obersable 从未被触发,并且 combineLatest 一直在等待。一个聪明而简单的解决方案。谢谢
【解决方案2】:

确保您遵循以下步骤

创建 onservable 数据

你有一个可观察的验证,你正在通过observable.next(value);推送数据

获取主题或 behourSubject 中的数据

您要在哪里获取声明主题类型变量的数据并通过订阅它来访问它。

private val: Subject = YourObservable;
private uiValue: string;

val.sunscribe((val) => {
   uiVal = val;
});

现在您可以在任何地方使用 uiVal,它会在每个间隔中更新。

您可以通过创建console.log 来分别测试这两个部分,以确保一切正常

【讨论】:

  • 正如我在描述中所写的那样,我使用两者的结果相同
  • 我在一秒钟前尝试过。遗憾的是没有改变任何东西
  • @Gesh 编辑了答案,确保你在 observable.next 中所做的一切都是正确的,然后订阅方
猜你喜欢
  • 2021-12-22
  • 1970-01-01
  • 2021-02-21
  • 2017-04-08
  • 2018-05-12
  • 1970-01-01
  • 2019-12-02
  • 2019-05-05
  • 2022-07-11
相关资源
最近更新 更多