Как использовать комбинироватьПоследний, когда один из потоков зависит от другого? - PullRequest
3 голосов
/ 01 октября 2019

У меня есть Angular-resolver, который извлекает данные из бэкэнда. Мне нужно выполнить следующие вызовы:

GetProject(projectId): Observable<IProject>
GetSites(projectId): Observable<ISites[]>
GetPersons(siteId): Observable<IPerson[]>

Я пытаюсь использовать combLatest, но не уверен, как использовать RxJ в моем сценарии. Я хочу, чтобы все запросы выполнялись до разрешения, но в качестве входных данных GetPersons () должен иметь идентификатор первого элемента в GetSites () result. Как это сделать?

Ответы [ 3 ]

3 голосов
/ 01 октября 2019

Похоже, вы просто хотите объединить несколько вызовов:

forkJoin([GetProject(projectId), GetSites(projectId)]).pipe(
  concatMap(([project, sites]) => {
    const siteId = /* whatever here */;
    return GetPersons(siteId);
  }),
).subscribe(...);

Это также зависит от того, хотите ли вы получить в наблюдателе все ответы или только последний. Если вы хотите получить все ответы, вам нужно связать GetPersons с map и добавить первые два ответа:

GetPersons(siteId).pipe(
  map(persons => [project, sites, persons]),
)
2 голосов
/ 01 октября 2019

Создайте тему воспроизведения:

const sub = new ReplaySubject(3);

Затем сделайте ваши звонки

this.getProject(1).pipe(
  tap(project => sub.next(project)),
  switchMap(project => this.getSites(1)),
  tap(sites => sub.next(sites)),
  switchMap(sites => this.getPersons(sites[0].id)),
  tap(person => sub.next(person))
);

Ваша тема воспроизведения будет содержать проект в качестве первого значения, сайты в качестве второго значения, человек в качестветретье значение.

Вы можете сделать это в формате combineLatest с BehaviorSubject.

const obs = new BehaviorSubject([]);
const add = val => obs.pipe(
  take(1),
  map(v => ([...v, val]))
).subscribe(v => obs.next(v));

this.getProject(1).pipe(
  tap(project => add(project)),
  switchMap(project => this.getSites(1)),
  tap(sites => add(sites)),
  switchMap(sites => this.getPersons(sites[0].id)),
  tap(person => add(person))
);

На этот раз возвращаемое значение будет массивом всех ваших значений.

Наконец, у вас есть сложный синтаксис для их объединения без темы.

this.getProject(1).pipe(
  switchMap(project => this.getSites(1).pipe(map(sites => ([project, sites])))),
  switchMap(([project, sites]) => this.getPersons(sites[0].id).pipe(map(person => ([project, sites, map])))),
);
0 голосов
/ 01 октября 2019
this.project$ = this.myService.getProject(projectId);
this.sites$ = this.myService.getSites(projectId);
this.persons$ = this.sites$.pipe(
  switchMap(
    (sites: ISites[]) => merge(...sites.map((site: ISites) => this.myService.getPersons(site.id))),
  ),
); // that should result in Observable<IPerson[][]>, you likely need to flatten it
...