如何使用 RxJS 从 firestore 集合中检索存储 downloadURL?

How do I retrieve a storage downloadURL from inside a firestore collection using RxJS?

我正在使用 Angular 12 和 AngularFire / Firebase 9(模块化)。我正在努力使用 RxJS 从存储中检索 downloadURL 并将其添加到集合结果的每个项目中。使用以下代码,我可以在“ZoneAwarePromise”下的控制台中查看数据,但无法通过模板查看数据。

const listCollection = collectionData(collection(this.firestore, 'lists'), {idField: 'id'});
this.lists = listCollection.pipe(take(1), map(lists => lists.map(async list => {
  const imgRef = ref(this.storage, list.metaImage);
  const coverImg = await getDownloadURL(imgRef);
  return {...list, coverImg}
})));

很难从您在这里写的内容中确定,但看起来 this.lists 是一个发出承诺列表的可观察对象。这就是 async 关键字的作用,它是创建承诺的语法糖。

您没有 taken/used 来自任何地方的承诺的 价值(即:您没有 await 在任何地方使用它们)。

一个解决方案是重写您的承诺,因为可观察对象使用 forkJoin 到 运行 您的可观察对象数组。

可能看起来像这样:

const listCollection = collectionData(collection(this.firestore, 'lists'), {idField: 'id'});

this.lists = listCollection.pipe(
  take(1), 
  map(lists => lists.map(list => {
    const imgRef = ref(this.storage, list.metaImage);
    return from(getDownloadURL(imgRef)).pipe(
      map(coverImg => ({...list, coverImg}))
    )
  })),
  switchMap(listsCalls => forkJoin(listsCalls))
);

使用 switchMap 组合结果确实有效;然而,它会在 Angular 中导致一些渲染阻塞问题(即在模板可以显示结果之前等待所有“列表”项目到 return getDownloadUrl())。从原始代码中删除“async”和“await”并向 Angular 模板添加“async”管道允许数据流动而不会呈现阻塞。

list.component.ts

const listCollection = collectionData(collection(this.firestore, 'lists'), {idField: 'id'});
this.lists = listCollection.pipe(take(1), map(lists => lists.map(list => {
  const imgRef = ref(this.storage, list.metaImage);
  const coverImg = getDownloadURL(imgRef);
  return {...list, coverImg}
})));

list.component.html

<div class="card" *ngFor="let list of lists | async">
  <div class="card-image">
    <img [src]="list.coverImg | async" />
  </div>
  <h2 class="card-title-lower">
    <a [routerLink]="['/list', list.id]">{{ list.title }}</a>
  </h2>
</div>