我对 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
属性中的数组。
答案 0 :(得分:1)
通常不建议混合使用 promise 和 observable。它们确实可以很好地协同工作,但它会使您的代码混乱和混乱。将 promise 转换为 observable 也非常简单。大多数创建/处理高阶 observable 的运算符都会为您进行转换。否则,from(promise)
也会返回一个 observable。
在这种情况下,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 实现的目标,因为在运行下一个 promise 之前await
每个 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(...
答案 1 :(得分:0)
你可以试试这个吗:
.pipe(map(querySnap => {
const ret = [];
querySnap.forEach(doc => {
const val = doc.get('otherUser').get().then(userData => {return userData});
ret.push(val);
});
return ret;
})).map(val => {
this.links = of(val);
});
基本上,您刚开始向 links 变量添加可观察流。