【问题标题】:Waiting for nested Observables from Store correctly in Angular 2在Angular 2中正确等待来自Store的嵌套Observables
【发布时间】:2021-03-19 14:44:30
【问题描述】:

我正在尝试创建一个具有嵌套依赖可观察对象的方法,其中第二个等待第一个。然后返回一个布尔值。

代码的作用是: 从 store 中获取资产列表,获取根资产,然后从数据库中获取状态,然后更新 UI。

但是发生的情况是,false 的值首先从外部订阅返回,然后 UI 被内部订阅正确更新,就像它应该做的那样。但它应该在完成时返回一个值true,而不是在完成之前返回一个false

我明白为什么会这样,我需要让外面的那个等待。在查看了与此处类似的许多其他问题后,我尝试使用switchMapresultSelector。但是我完全不知道如何在这种情况下正确使用它们,tap

任何建议将不胜感激。

getAndUpdateHexStatus (startTime, endTime): Observable<boolean> {
  this.store.pipe(
      select((assets) => assets.dashboard.assets), //get the assets
      tap((assets) => {
        var rootAsset = assets.filter((value) => this.isRootAsset(value)); //get the root asset
        if (rootAsset) {
          this.getDetailDataForAssetAndDates(rootAsset[0].assetId, new Date(startTime), new Date(endTime)) //get status data from the DB.
            .subscribe((data) => {
              this.updateAssetStatus(data); //Update the UI
              return of(true);
            });
        }

      }),
      takeUntil(this.componentDestroyed$)
    )
    .subscribe();
    return of(false);
}

【问题讨论】:

    标签: angular typescript rxjs observable


    【解决方案1】:

    你很接近。您将在函数执行时立即返回 of(false),因此它首先被返回。

    相反,您需要使用像switchMap 这样的高阶映射运算符,并在它的主体内决定返回什么。如果条件为真,则返回 getDetailDataForAssetAndDates() 并通过管道输入 map 运算符以更新 UI 并返回 true。或者如果条件为假,则使用of() 返回false,因为switchMap 需要返回一个observable。

    getAndUpdateHexStatus(startTime, endTime): Observable<boolean> {
      return this.store.pipe(
        select((assets) => assets.dashboard.assets), //get the assets
        switchMap((assets: any) => {
          rootAsset = assets.filter((value) => this.isRootAsset(value));
          return (!!rootAsset)
            ? this.getDetailDataForAssetAndDates(rootAsset[0].assetId, new Date(startTime), new Date(endTime)).pipe(
                map(data => {
                  this.updateAssetStatus(data);
                  return true;
                })
              )
            : of(false)
        })
      );
    }
    

    【讨论】:

      【解决方案2】:

      这是(大致)我将如何实现它:

      有两点需要注意,你的函数返回一个 observable。这意味着您很少想在该函数中的任何位置使用subscribe。您的更新资产状态作为副作用处理,因此我将其留在了 tap 运算符中。

      通常,可以通过 mergeMap 处理嵌套订阅,但通常最好使用 switchMap 或 concatMap 来保存网络或保证顺序。我认为在这种情况下,这是次要问题。

      function getAndUpdateHexStatus (startTime, endTime): Observable<boolean> {
        return this.store.pipe(
          // get the assets
          select((assets) => assets.dashboard.assets), 
      
          // merge observable that emits true/false
          mergeMap(assets => {
            // get the root asset
            const rootAsset = assets.filter(v => this.isRootAsset(v));
            return rootAsset?.length > 1 ?
              // get status data from the DB.
              this.getDetailDataForAssetAndDates( 
                rootAsset[0].assetId, 
                new Date(startTime), 
                new Date(endTime)
              ).pipe(
                // Update UI
                tap(data => this.updateAssetStatus(data)),
                // UI updated, emit true
                mapTo(true)
              ) : 
              // No root asset, just emit false
              of(false)
          }),
      
          take(1)
        );
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-08-24
        • 2017-03-20
        • 2018-12-20
        • 2019-02-18
        • 2019-10-27
        • 1970-01-01
        • 2019-08-04
        • 2017-05-25
        相关资源
        最近更新 更多