ngFor 中嵌套异步的最佳实践?
Posted
技术标签:
【中文标题】ngFor 中嵌套异步的最佳实践?【英文标题】:Best practices for nested async inside of ngFor? 【发布时间】:2021-11-15 10:51:12 【问题描述】:假设我有一个汽车清单:
const cars: Array<carId: number> = [carId: 1, carId: 2];
然后我在模板中渲染它们:
<div *ngFor=“let car of cars”></div>
在该模板内部,我想从返回可观察对象的方法中获取一些动态图像路径:
<div *ngFor=“let car of cars”>
<img [src]=“getImagePath(car) | async”>
</div>
getImagePath(car: carId: number): Observable<string>
return //some service request that brings back a url based on the carId
对于状态管理和存储,我使用的是 Firebase。我的所有图片都存储在一个存储桶中,我可以通过为我的服务提供一个 carId 来获取它们,该 carId 使用它来获取下载 URL。
我想避免在第一次保存文件时使用 downloadURL 更新 Firestore,因为我会将它们存储在子集合中,并且由于 Firestore 的性质,将它们从那里拉出来已经很痛苦了。
有没有办法更有效地做到这一点?如果列表开始增长,上面的代码肯定会让浏览器爬起来……对吧?
【问题讨论】:
也许我不明白;但是你为什么认为浏览器会爬起来呢?显然,如果你有大量的汽车列表,你会得到很多div
s;然后您将下载许多图像......但这就是您正在构建的页面的性质(如果您不分页) - 不是 Angular 代码的低效率。另外,我不明白 Firestore 与您的问题有何关联
不是吗?如果我有一百辆车怎么办? DOM 渲染时不是有一百个活动订阅吗?我只提到 Firebase 是为了避免建议存储图像路径并将它们包含在汽车对象中的响应。
【参考方案1】:
您可以将其变成一个可观察对象并订阅一次,然后将返回的数组显示到您的 html 中,而不是直接在每个 img 元素上调用请求。
我使用了几个 RXJS 运算符来得到你想要的。
mergeMap
扁平化内部 observable
of
将 cars 数组转换为 observable
map
将 cars 数组转换为具有相应汽车图像路径的新数组
forkJoin
- 我们将多个请求封装到一个 observable 中,并且只有在收到所有请求的响应时才会返回。
这当然只是一种方法,可能还有其他更好的方法。
getCarImages()
const cars: Array <
carId: number;
> = [
carId: 1,
,
carId: 2,
,
];
of(cars)
.pipe(
mergeMap((e) =>
return forkJoin(
e.map((item) => this.apiService.getCarImages(item.carId))
).pipe(
map((paths) =>
console.log(paths);
return e.map((car, index) => (
...car,
imagePath: paths[index],
));
)
);
)
)
.subscribe((res) =>
this.cars = res;
console.log(this.cars);
);
HTML:
<div *ngFor="let car of cars">
<img [src]="car?.imagePath" />
</div>
我创建了一个stackblitz 来模拟解决方案。
【讨论】:
@katysha - 我认为你的方法更简单更好以上是关于ngFor 中嵌套异步的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章