如何用for循环正确地将RxJS观测值链在一起?

我有一个projectService来检索项目。每个项目又有方法来检索相应的标签和模块。

我想做的是在实例属性projects.Project[]中填充所有对应的标签和模块。Project[]中填充所有对应的标签和模块,当所有的东西都填充完毕后,再调用另一个方法,这个方法取决于数据。

我知道我的方法是行不通的,因为我的map操作在for循环中的观测值完成之前就返回了project,但我不知道如何正确的操作。

class ProjectService {
  getAll(): Observable<Project[]> {...}
}
class Project {
  tagCollection: Tag[];
  moduleCollection: Module[];

  getTags(): Observable<Tag[]> {...}
  getModules(): Observable<Module[]> {...}
}
this.projectService
  .getAll()
  .pipe(
    map(projects => {
      for (const project of projects) {
        project.getTags().subscribe(tags => {
          project.tagCollection = tags;
        });
        project.getModules().subscribe(modules => {
          project.modules = modules;
        });
      }
      return projects;
    })
  )
  .subscribe(projects => {
    this.projects = projects;
    this.someOtherMethod();
  });

更新

我已经尝试了两种解决方案,并对它们进行了编辑,以保留项目类型并使用类似的编码风格。这两种解决方案都可以工作,并且在我的项目上下文中似乎做了同样的事情。但我不确定哪种解决方案更好,我所做的编辑是否打破了任何反应式的最佳实践。谁能详细说明一下?

Reqven的解决方案1

this.projectService
  .getAll()
  .pipe(
    switchMap(projects =>
      combineLatest(
        projects.map(project =>
          combineLatest([project.getTags(), project.getModules()]).pipe(
            map(([tags, modules]) => {
              project.tagCollection = tags;
              project.modules = modules;
              return project;
            })
          )
        )
      )
    )
  )
  .subscribe(projects => {
    console.log(projects);
    this.projects = projects;
    this.someOtherMethod();
  });

NateDev的解决方案2

this.projectService
  .getAll()
  .pipe(
    mergeMap(projects => from(projects)),
    mergeMap(project => 
      combineLatest([project.getTags(), project.getModules()]).pipe(
        map(([tags, modules]) => {
          project.tagCollection = tags;
          project.modules = modules;
          return project;
        })
      )
    ),
    toArray()
  )
  .subscribe(projects => {
    console.log(projects);
    this.projects = projects;
    this.someOtherMethod();
  });

解决方案:

有很多不同的方法来执行异步的批量调用。

所以我喜欢做的是扁平化我的数据,因为我相信在一个更扁平的结构上执行操作更容易。当我完成了对对象的操作之后,我使用 toArray 经营者

如果你对我使用的运营商有任何疑问,请随时询问。我强烈建议你去玩玩不同的产品。rxjs转换运算符.

要知道我下面的代码绝对不是 最佳 解决办法,但效果不错!

希望对你有用 StackBlitz

import { Component, Input, OnInit } from '@angular/core';
import { Observable, of, from, combineLatest } from 'rxjs'
import { delay, map, mergeMap,switchMap, toArray } from 'rxjs/operators';

@Component({
  selector: 'hello',
  template: `<h1>Hello {{name}}!</h1>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent implements OnInit {
  @Input() name: string;

  data: Partial<Project>[] =  [
    { name: 'foo'},
    { name: 'foo'}
  ]

  ngOnInit() : void {
    this.getProjects().pipe(
      mergeMap(projects => from(projects)),
      mergeMap((project) => {
        const tag$ = this.getTagsByProjectName(project.name);
        const module$ = this.getModuleByProjectName(project.name);
        return combineLatest([tag$,module$]).pipe(map(([tag,module]) => ({...project, tag, module})))
      }),
      toArray()
    ).subscribe({
      next: projects => {
        console.log(projects);
        this.name = JSON.stringify(projects);
      }
    })
  }

  getProjects() : Observable<Partial<Project>[]> {
    return of(this.data).pipe(
      delay(100)
    )
  }

  getTagsByProjectName(name: string){
    const tag = 'bar';
    return of(tag).pipe(delay(100));
  }

  getModuleByProjectName(name: string){
    const module = 'baz';
    return of(module).pipe(delay(100));
  }
}

interface Project {
  name: string; 
  tag: string; 
  module: string;
}

给TA打赏
共{{data.count}}人
人已打赏
未分类

jQueryUI自动完成与默认的文本。

2022-9-9 10:16:35

未分类

如何将一个未知维度的张量乘以tensorflow变量?

2022-9-9 10:16:37

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索