Angular 可观察管道 return 数组
Angular observable pipe return array
我是 Angular 9 的新手,基本上我想知道如何 return 来自异步源的对象数组?我目前有一个 firestore 查询,其中 returned 的文档有一个我希望呈现其数据的引用。
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>
当前 return 是错误:InvalidPipeArgument:'[object Promise]' for pipe 'AsyncPipe'
当我删除 HTML 中的异步管道时,它 return 是一个 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
属性.
你能试试这个吗:
.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);
});
基本上,您刚开始将可观察流添加到链接变量。
通常不建议混合使用 promises 和 observables。它们确实可以很好地协同工作,但它会使您的代码混乱和混乱。将 promise 转换为 observable 也非常简单。大多数 create/deal 具有高阶可观察量的运算符都会为您进行转换。否则,from(promise)
return 也是一个可观察对象。
使用 forkJoin
在这种情况下,forkJoin
毫无怨言地接受了Promise
的数组。
forkJoin
将同时 运行 所有承诺和 return 一系列响应 once/if 它们都是 complete/resolve.
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
也可以接受 promises 作为参数。我们使用扩展运算符 (...) 将数组转换为参数列表。
这实际上更接近您通过承诺实现的目标,因为您 await
每个承诺都在 运行 下一个承诺之前。这将 运行 你的承诺一次一个(而不是同时, 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(...
我是 Angular 9 的新手,基本上我想知道如何 return 来自异步源的对象数组?我目前有一个 firestore 查询,其中 returned 的文档有一个我希望呈现其数据的引用。
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>
当前 return 是错误:InvalidPipeArgument:'[object Promise]' for pipe 'AsyncPipe' 当我删除 HTML 中的异步管道时,它 return 是一个 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
属性.
你能试试这个吗:
.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);
});
基本上,您刚开始将可观察流添加到链接变量。
通常不建议混合使用 promises 和 observables。它们确实可以很好地协同工作,但它会使您的代码混乱和混乱。将 promise 转换为 observable 也非常简单。大多数 create/deal 具有高阶可观察量的运算符都会为您进行转换。否则,from(promise)
return 也是一个可观察对象。
使用 forkJoin
在这种情况下,forkJoin
毫无怨言地接受了Promise
的数组。
forkJoin
将同时 运行 所有承诺和 return 一系列响应 once/if 它们都是 complete/resolve.
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
也可以接受 promises 作为参数。我们使用扩展运算符 (...) 将数组转换为参数列表。
这实际上更接近您通过承诺实现的目标,因为您 await
每个承诺都在 运行 下一个承诺之前。这将 运行 你的承诺一次一个(而不是同时, 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(...