网站搜索

typescript - RxJS:等待 Subscription 接收下一个值


我在一个 Angular 项目中使用 RxJS,并且我有一个对定期发出值的 Observable 的 Subscription。

在同一个组件中,我也使用 RxJS(结合 Angular http 客户端)来进行网络调用并订阅它。

我想做的很简单:当我进行网络调用并返回结果时,我想等待 Subscription 接收到下一个值之后再处理结果。让我们通过一个代码示例更好地看看:

假设我有这个订阅,它以固定间隔从可观察对象接收新值:

tenantStatusSub: Subscription;

我想做的事情在评论中解释如下:

this.httpClient.get<any>(...).subscribe({
  next: result => {
      /* I want to wait here for tenantStatusSub to receive a value before proceeding */
  },
  error: err => {
    //...
  }
});

我相信一定有一种直接的方法可以做到这一点,但我还在学习 RxJS,所以我不确定哪种方式是最好的/最干净的。

答案#1

我认为你不能直接等待 tenantStatusSub-subscription 本身。然而,你可以等待 tenantStatusSub-subscription 所指向的可观察对象的下一次发射。我建议你使用 switchMap() 直接将你的 HTTP 请求链到接收连续发射的可观察对象上。此外,你可以使用 first(),在第一个值到达后触发“取消订阅”:

tenantStatusObs$: Observable<any> = observableThatReceivesAFlowOfValues;

ngOnInit(): void {
    this.httpClient.get<any>('http://www.some-url.com').pipe(
        switchMap(resultFromApi => {
            return this.tenantStatusObs$.pipe(
                first(), // unsubscribes after the first value has been emitted
                tap(tenantStatus => {
                    console.log('Tenant Status:', tenantStatus);
                    console.log('Result from API:', resultFromApi);
                })
            )
        })
    )
    .subscribe();
}

答案#2

CombineLatest 可以做到这一点,但效果不太好。如果 tenantStatusSub 在获取响应的时间间隔内定期发出数据,这个方法是可行的。即便如此,下面使用 switchMap 的方法(虽然稍微复杂一些)应该会更稳健。

combineLatest([
  tenantStatusSub,
  this.httpClient.get<any>(...)
]).pipe(
  skip(1),
  take(1)
).subscribe({
  next: result => {
    // both values in result here
  },
  error: err => {
    //...
  }
});

更新:

一旦你获得了 HTTP 响应,获取下一个租户状态并将两个值合并为单一输出。由于切换到 tenantStatusObs$ 是长期的,你需要通过 take(1) 取消订阅。

this.httpClient.get<any>(...).pipe(
  switchMap(httpRes => this.tenantStatusObs$.pipe(
    map(tenantStatus => ({ httpRes, tenantStatus })
  )),
  take(1)
).subscribe({
  next: ({ httpRes, tenantStatus }) => {
    // both values available here
  },
  error: err => {
    //...
  }
});

旁白:

在这种情况下,你可以在 map 或 switchMap 操作符之后写 take(1)。它们会产生相同的输出。然而,从语义上讲,它们的含义是不同的。

  • After map 的意思是:“每个 tenantStatusSub 发射最多一个(配对的)发射”
  • switchMap 之后意味着:“最多一次(配对)发射”