【问题标题】:combineLatest doesn't subscribe to parameter Observables, doesn't deliver datacombineLatest 不订阅参数 Observables,不传递数据
【发布时间】:2017-10-07 03:33:15
【问题描述】:

我有一个相当常见的用例。我正在从 FirebaseDatabase 加载一组对象,并从 Firebase Storage 附加图像。

FirebaseDatabase 根据查询返回一个 Observable。每次数据库中的数据发生变化时,Observable 都会发出一个更新的查询结果。我还通过映射到每个条目的 [Domain, ImagePromise] 元组,将来自 Storage api 的 Promise 附加到结果中的每个条目

getDomainObj(){
   return this.af.database.list(this.listRef)
    .map((mps: Domain[]) => 
       mps.map((mp: Domain) =>  
         [mp, this.getImage(mp['$key'])]));
}

两个问题:

  1. 有些 mps 没有图像。
  2. 由于图像不在 firedb 中,因此 observable 不会在图像更改时发出。为了解决这个问题,我添加了一个云功能来在每次图像更新时发送推送通知(在这个问题的范围之外,它可以工作,所以不需要进入它)。每个 mp 都是它自己的 PubSub 主题,我们在客户端订阅该主题,并获得一个更新的 Observable,每次上传特定 mp 的图像时都会发出更新

我通过映射来解决它们

this.mpSvc.getDomainObj()
  .map((tupleArray: [Domain, Promise<string>][]) => 
    tupleArray.map(([mp, imageSrcPromise]: [Domain, Promise<string>]) => {
      return [mp, 
           Observable.fromPromise(imageSrcPromise) // get initial image
            .startWith(null) // make sure that it emits at least once
            .concat( // updates
              this.mpSvc.signUpForPictureUpdates(mp['$key'])
              .map(([id, imageSrc]: [string, string]) => imageSrc))

      ];
    })
)

mpSvc.signUpForPictureUpdates 返回一个由 domainId-imageSrc 元组组成的 Observable,每次重新上传域的图像时都会发出该元组

现在的最终目标是拥有一个 [Domain, imageSrc] 数组的 Observable,每当任何一个 Domain 对象的图像发生变化,或任何 Domain 对象发生变化,或查询发生变化。

首先我再次重新映射,而不是发出 [Domain,Observable] 对的数组,而是发出 Observable

的数组
.map((tupleArray: [Domain, Observable<string>][]) => 
  tupleArray.map(([mp, imageSrcObservable]: [Domain, Observable<string>]) => 
     imageSrcObservable.map((imageSrc: string) => [mp, imageSrc])))

现在我有一组 Observable 对的 Observable。每次域或查询结果发生变化时,父级 Observable 都会发出,每次特定域的图像发生变化时,子级都会发出。

对于最后一步,我将可观察的子对象组合成一个可观察对象并将其切换映射。

.switchMap((imageObservables: Observable<[Domain, string]>[]) => 
  Observable.combineLatest(imageObservables)
)

结果被正确订阅(实际上,它通过ngFor|async显示在Angular模板中,但这也在范围之外)。

很遗憾,结果并非预期的那样。实际上,我有四个来自查询的结果对象,两个带有图像,两个没有。我看到的情况并不一致 - 有时会加载两个图像,有时会加载一个,而且大多数情况下都不加载。

具体来说,如果我要像这样在末尾添加一个日志记录行:

.do(x => console.log('final', x), x => console.error('finalerror', x), () => console.log('finalcomplete'));

我总是在 imageSrc 中获得至少一个带有空值的日志行,但几乎没有其他行带有已解析的真实 imageSrcs。

在最后一步之前订阅(combineLatest)正确获取所有数据

我做错了什么?

编辑:在进一步研究之后,问题肯定出在combineLatest。我尝试用imageObservables[1].map(x=&gt;[x]) 替换combineLatest 并且它工作得很好(尽管当然只返回一个值而不是数组。此外,单步执行combineLatest 导致我遇到一些奇怪的关闭,因为在任何时候都需要关闭?

【问题讨论】:

    标签: angular rxjs observable combinelatest


    【解决方案1】:

    好的,我发现了问题。如果 Promise 拒绝,fromPromise 将抛出错误。因此,其中一个孩子在 getImage 没有得到图像时出错,导致 combineLatest 完成。

    我是这样解决的

    Observable.fromPromise(imageSrcPromise) // get initial image
    .catch(() => Observable.empty()) // <-- fix 
    .startWith(null) // and so forth...
    

    这就是为什么有时它会正确发射,有时却没有。如果请求首先加载图像的域对象,它们将显示。如果无图像对象首先返回,则流将结束。

    【讨论】:

      猜你喜欢
      • 2020-01-23
      • 2017-04-26
      • 2018-08-30
      • 1970-01-01
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      • 2020-08-12
      • 1970-01-01
      相关资源
      最近更新 更多