如何使用 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>
我正在使用 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>