在对对象进行操作时链接递归 RxJS 可观察对象

Posted

技术标签:

【中文标题】在对对象进行操作时链接递归 RxJS 可观察对象【英文标题】:Chaining recursive RxJS observables while operating on object 【发布时间】:2020-12-22 13:17:48 【问题描述】:

我的后端有两个 graphql 查询:familiyTreeQuery 它返回一个家谱作为带有孩子的节点,它也可以有孩子等等,personPicturesQuery($name: string) 返回给定人的图片。

我的目标是调用familyTreeQuery,迭代树,如果这个人叫Alice,那么我想为这个人调用personPicturesQuery,并将信息添加到树中的节点。应该对树中的所有 Alice 都这样做。

我的问题是,获取图片的调用是异步发生的,因此在将信息添加到节点之前返回数据。 我未能按照this question 中的建议使用flatMap,因为获取图片的调用是在迭代树时发生的,我无法在familyTreeQuery 的管道方法中调用它。

public getContext(): Observable<TreeNode> 
  return this.familyTreeQuery.watch().valueChanges.pipe(
    map(result => 
      const familyTree = result.data.familyTree;;
      this.addPicturesToAlice(familyTree);
      return familyTree;
      
    )
  )


private addPicturesToAlice(node: TreeNode) 
  if (node.name === 'Alice') 
    this.fetchPictures(node.id).subscribe(pictures => 
      node.pictures = pictures;
    )
  
  if (node.children && node.children.length > 0) 
    for (const childNode of node.children) 
      this.addPicturesToAlice(childNode);
    
  


private this.fetchPictures(personId): Observable<Picture[]> 
  return this.personPicturesQuery.fetch(id: personId).pipe(
    map(result => 
      return result.data.personPictures;
    )
  )

据我了解,我不应该在 addPicturesToAlice 方法中调用 subscribe,但我是 Angular 和 RxJS 的新手,并没有找到一种方法来完成这项工作。

【问题讨论】:

structuredTrees 定义在哪里? 应该是familyTree,编辑了问题 你可以考虑在这里从 Observable 切换到 Promise 并使用 async-await 方法。 如代码注释中所述,您可以假装它确实如此。我简化了问题的代码,实际上它处理其他东西 为了回答你的问题,理解它的作用是非常有必要的,所以我们可以重构addPicturesToAlice 【参考方案1】:

您可以通过创建一个 observables 数组并递归地传递它,然后使用 forkJoingetContext 中订阅它来实现这一点,如下所示:

public getContext(): Observable<TreeNode> 
  return this.familyTreeQuery.watch().valueChanges.pipe(
    switchMap(( data:  familyTree  ) => forkJoin(this.addPicturesToAlice(familyTree)))
  )


private addPicturesToAlice(node: TreeNode, observables: Observable<Picture[]>[] = []): Observable<Picture[]>[] 
  if (node.name === 'Alice') observables.push(
    this.fetchPictures(node.id).pipe(tap(pictures => node.pictures = pictures))
  )

  if (node.children?.length) 
    for (const childNode of node.children) 
      this.addPicturesToAlice(childNode, observables);
    
  

  return observables;


private fetchPictures(personId: number): Observable<Picture[]> 
  return this.personPicturesQuery
    .fetch( id: personId )
    .pipe(map(result => result.data.personPictures))

希望它足够清楚。

【讨论】:

看来这样可以了,非常感谢!还有一个问题,如果familyTreeQuery 返回多个家族树,我该怎么办?在switchMap 之前我可以使用另一种 RxJS 方法吗? 请看看这个***.com/questions/42482705/…

以上是关于在对对象进行操作时链接递归 RxJS 可观察对象的主要内容,如果未能解决你的问题,请参考以下文章

Angular/RxJS:带有可观察对象的嵌套服务调用

RxJs:根据字段值更改创建可观察对象

Angular RxJS入门笔记 (Observable可观察对象Subscribe订阅Observer观察者Subscription对象)

rxjs中常用的操作符

RxJS - 连接并合并两个可观察对象

在 Angular 6 中使用 rxjs 可观察对象的目的是啥?与 async/await 相比,rxjs 的优势是啥? [复制]