2017-05-09 69 views
0

我有一个相当常见的用例。我从FirebaseDatabase加载对象数组,并从Firebase存储中附加图像。combineLatest不订阅参数Observables,不提供数据

FirebaseDatabase基于查询返回Observable。每次数据库中的数据都会改变,Observable会发出更新后的查询结果。我还从存储API通过映射附加承诺到结果的每个条目的[域,ImagePromise]元组的每个条目

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

两个问题:

  1. 一些议员没有一个图像。
  2. 由于图像不在图像中,因此图像变化时,可观察图像不会发出。为了解决这个问题,我添加了一个Cloud函数来发送每个图像更新的推送通知(这个问题的范围之外,它的工作原理,所以不需要进入)。每个MP是自己的PubSub的话题,我们在客户端订阅主题,以及

我通过映射

解决这些问题都得到可观察到的,将发出每次图像特定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元组,将发射每个域的图像将得到重新上传

现在最终目标是具有可观察到的[域,imageSrc]阵列的时间的,每次都会发出Domai中任何一个图像n对象更改或任何Domain对象更改,或者查询结果发生更改。

首先我再次重新映射,而不是发射[域,可观察]对的阵列,发射可观察<的阵列[域,imageSrc]>

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

我现在有一个可观察的阵列的对的可观察性。每当一个域或查询结果将发生变化时,父级Observable就会发出,并且每当特定域的映像发生更改时,子级都会发出。

对于最后一步,我将observable的子项组合到一个observable中,并将switchMap组合到它中。

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

结果正确subsribed来(事实上,它显示在通过ngFor角模板|异步,但是这也是范围之内)。

不幸的是,结果不是预期的结果。实际上,我有四个来自查询的结果对象,两个有图像,两个没有。我所看到的并不一致 - 有时两种图像都加载,有时是一种,最常见的是两种。

具体来说,如果我是一个记录行添加到末尾,像这样:

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

我总是至少有一个日志符合在imageSrc空,但几乎没有过额外的线条与解决实际imageSrcs 。

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

我在做什么错?

编辑:寻找到这个更长时间后,这个问题肯定是用combineLatest。我试着用imageObservables[1].map(x=>[x])更换combineLatest和它完美的作品(尽管当然只返回一个值,而不是数组的。此外,通过combineLatest步进使我有些收盘这是奇怪的,因为需要在任何时候被关闭呢?

回答

2

好吧,我发现这个问题。如果承诺拒绝fromPromise将抛出一个错误。因此,一个孩子error'ed出来时,它getImage没有得到的图像,这导致combineLatest完成。

我像这样固定它

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

这就是为什么有时它正常发出,有时则没有。如果先加载图像的Domain对象请求显示。如果无图像对象首先返回,则该流将结束。