typescript RxJS:等待订阅接收下一个值

q8l4jmvw  于 2022-12-27  发布在  TypeScript
关注(0)|答案(2)|浏览(241)

我在一个Angular项目中使用RxJS,我有一个Subscription到一个Observable,它们以固定的间隔发出值。
在同一个组件中,我还使用RxJS(与Angular http客户端结合使用)进行Web调用并订阅它。
我想做的很简单:当我进行Web调用并且它返回了一个结果时,我希望等到Subscription接收到下一个值后再处理结果。让我们通过一个代码示例更好地了解这一点:
假设我有一个订阅,它定期从Observable接收新值:

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,所以我不确定最好/最干净的方法是什么。

plupiseo

plupiseo1#

我不认为你可以等待tenantStatusSub-subscription本身,但是你可以等待tenantStatusSub-subscription引用的观察对象的下一次发射,我建议你使用switchMap()将你的http请求直接链接到接收连续发射流的观察对象,而且你可以使用first(),在第一个值到达后触发“unsubscribe”:

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();
}
svgewumm

svgewumm2#

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 => {
    //...
  }
});

旁白:
在这种情况下,你可以在mapswitchMap操作符之后写take(1),它们会创建相同的输出,但是在语义上,它们有不同的含义。

      • Map后表示:**"每个tenantStatusSub发射最多一个(配对)发射"
      • switchMap之后表示:**"最多一次(成对)发射"

相关问题