angular - 角度可观察管道返回数组
问题描述
我对 Angular 9 相当陌生,基本上我想知道如何从异步源返回一组对象?我目前有一个 firestore 查询,其中返回的文档具有我希望呈现其数据的引用。
ngOnInit
this.currentUserRef.collection('links', ref => ref.where('pendingRequest', '==', false)).get()
.pipe(map(querySnap => {
const ret = [];
querySnap.forEach(doc => {
const val = doc.get('otherUser').get().then(userData => {return userData});
ret.push(val);
});
return ret;
})).subscribe(val => {
this.links = val;
});
HTML
<ion-item *ngFor="let link of links | async">
<ion-avatar slot="start">
<img [src]="getImage(link.get('profilepic'))">
</ion-avatar>
<ion-label>
<h2>{{link.get('name')}}</h2>
<p>{{link.get('bio')}}</p>
</ion-label>
<ion-checkbox id="{{link.id}}"></ion-checkbox>
</ion-item>
这当前返回错误: InvalidPipeArgument: '[object Promise]' for pipe 'AsyncPipe' 当我在 HTML 中删除异步管道时,它返回 zoneawarepromise。
编辑
this.links = this.currentUserRef.collection('links', ref => ref.where('pendingRequest', '==', false)).get()
.pipe(map(querySnap => {
const ret = [];
querySnap.forEach(async doc => {
const val = await doc.get('otherUser').get().then(userData => {return userData});
ret.push(val);
});
return ret;
}));
这现在可行,但是由于数组,我不知道该解决方案对于大量文档的效率和可扩展性
ret
注意:querySnap 是一个对象,它具有内置的 forEach 方法来遍历其docs
属性中的数组。
解决方案
通常不建议混合使用 Promise 和 observables。它们确实可以很好地配合使用,但它会混淆并混淆您的代码。将 promise 转换为 observable 也非常简单。大多数创建/处理高阶 observables 的操作符将为您进行转换。否则,from(promise)
也返回一个 observable。
使用 forkJoin
在这种情况下,forkJoin
接受一系列Promise
毫无怨言的。
forkJoin
将同时运行所有承诺并返回一个响应数组一次/如果它们都完成/解决。
this.links = this.currentUserRef.collection(
'links',
ref => ref.where('pendingRequest', '==', false)
).get().pipe(
mergeMap(querySnap => forkJoin(
querySnap.docs.map(
doc => doc.get('otherUser').get()
))
)
);
使用连接
concat
也可以接受 Promise 作为参数。我们使用扩展运算符 (...) 将数组转换为参数列表。
这实际上更接近于您通过 Promise 实现的目标,因为您await
在运行下一个 Promise 之前每个 Promise。这将一次运行你的承诺(而不是同时运行,方式forkJoin
是
this.links = this.currentUserRef.collection(
'links',
ref => ref.where('pendingRequest', '==', false)
).get().pipe(
mergeMap(querySnap => concat(
...querySnap.docs.map(
doc => doc.get('otherUser').get()
))
),
toArray()
);
旁白:清理你的承诺代码
这个:
this.links = this.currentUserRef.collection('links', ref => ref.where('pendingRequest', '==', false)).get()
.pipe(map(querySnap => {
const ret = [];
querySnap.forEach(async doc => {
const val = await doc.get('otherUser').get().then(userData => {return userData});
ret.push(val);
});
return ret;
}));
相当于
this.links = this.currentUserRef.collection(
'links',
ref => ref.where('pendingRequest', '==', false)
).get().pipe(
map(querySnap => {
const ret = [];
querySnap.forEach(async doc =>
ret.push(await doc.get('otherUser').get())
);
return ret;
})
)
基本上,如果你使用 await,你不需要.then(...
推荐阅读
- javascript - 仅更改单击按钮的颜色,其他返回原始颜色 VueJS
- javascript - 错误未定义 Express 错误中间件
- apache-kafka - 适用于 Oracle 的 Debezium 连接器 - 未在桌面上获取新项目或更新
- java - 如何模拟所需的相关实体?
- python - 在 MacOS 上使用 Spotlight 从 .command 文件运行 Python 脚本
- scala.js - org_scalajs_dom_raw_HTMLDocument(...).createRange 不是函数
- macos - 将带有符号链接的 tar.gz 文件解压缩到另一个目录中
- c - 如何从 C 程序函数调用包含简单函数的程序集文件?
- javascript - 在javascript中以编程方式转义/脚本结束标记
- kubernetes - gRPC 节点微服务与 istio 网格中的另一个微服务通信