角度可观察管道返回数组

时间:2021-01-06 05:46:40

标签: angular google-cloud-firestore rxjs observable angular9

我对 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 属性中的数组。

2 个答案:

答案 0 :(得分:1)

通常不建议混合使用 promise 和 observable。它们确实可以很好地协同工作,但它会使您的代码混乱和混乱。将 promise 转换为 observable 也非常简单。大多数创建/处理高阶 observable 的运算符都会为您进行转换。否则,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 实现的目标,因为在运行下一个 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 变量添加可观察流。

相关问题