RxJs运营商如何处理相关的http服务调用订阅?

时间:2019-02-19 08:01:29

标签: angular rxjs

我有一个名为fetchSeviceProviders的函数,该函数将向我返回服务提供商的列表,并让我通过调用其他服务来设置服务提供商的徽标。我通过使用两个订阅实现了这一点。

在第一次订阅时,我得到了列表。然后,我将其映射并通过所有服务提供商的ID调用fetchServiceProviderLogo。

可以通过一个订阅完成此操作吗?我的方法可以吗?如果没有,那是什么问题?一些rxjs运算符如何执行此操作?

我尝试了map和flatMap运算符,但没有任何线索。

fetchServiceProviders ()
{
    this.subscribers.fetchServiceProvidersLogoSub = this.serviceProviderService.fetchServiceProviders( new Map() ).subscribe(
        data =>
        {
            this.providers = data._embedded.serviceProviders;
            this.providers.map(
                provider =>
                {  
                    this.subscribers.fetchServiceProvidersLogoSub =
                        this.serviceProviderService.fetchServiceProviderLogo( { 'id': provider.id } ).subscribe(
                            logo =>
                            {
                                this.createIndividualLogoFromBlob( provider, logo );
                            }
                        );
                }
            );
        }
    )
}

3 个答案:

答案 0 :(得分:1)

如果所有可观测对象都已完成并且this.serviceProviderService.fetchServiceProviderLogo的调用顺序无关紧要,则可以组合使用switchMap(或mergeMap)和merge。如果您的提取请求全部完成,您也不必取消订阅。

fetchServiceProviders () {
  this.serviceProviderService.fetchServiceProviders(new Map())
    .pipe(
      map(data => data._embedded.serviceProviders),
      mergeMap(providers => merge(
        providers.map(provider =>
          this.serviceProviderService.fetchServiceProviderLogo({ 'id': provider.id })
           .pipe(map(logo => ({ provider, logo })))
        )
      ))
    )
    .subscribe(({ provider, logo }) => this.createIndividualLogoFromBlob(provider, logo));
}

您可以使用merge而不是forkJoin来并行执行this.serviceProviderService.fetchServiceProviderLogo调用。

fetchServiceProviders () {
  this.serviceProviderService.fetchServiceProviders(new Map())
    .pipe(
      map(data => data._embedded.serviceProviders),
      mergeMap(providers => forkJoin(
        providers.map(provider =>
          this.serviceProviderService.fetchServiceProviderLogo({ 'id': provider.id })
           .pipe(map(logo => ({ provider, logo })))
        )
      ))
    )
    .subscribe(providerLogos =>
       providerLogos.forEach(({ provider, logo }) => this.createIndividualLogoFromBlob(provider, logo))
    );
}

答案 1 :(得分:0)

在您的代码中,您正在为每个serviceProvider进行预订。 如果您想一次完成所有操作,则可以查看合并运算符:https://www.learnrxjs.io/operators/combination/merge.html

答案 2 :(得分:0)

这是一个简单的例子。您可以考虑getItemsgetStreetNameById您的提供商。

import { of, from } from 'rxjs';
import { switchMap, groupBy, map, mergeMap } from 'rxjs/operators';

function getItems() {
  return of([
    { streetId: 1, person: 'Person 1' },
    { streetId: 2, person: 'Person 2' },
    { streetId: 1, person: 'Person 3' },
  ]);
}

function getStreetNameById(id: number) {
  console.log('requesting street name for ', id);
  return of('Street ' + id);
}

getItems().pipe( //get all the items
  switchMap(items => from(items)), //create a new stream with each item from the list
  groupBy(item => item.streetId), //group by the streetId (we want to request the street name once per id
  mergeMap(group => { //merge all the transformed groups back into one stream
    return getStreetNameById(group.key) //request the street name by id
      .pipe(
        switchMap(streetName => group.pipe( //merge the street name back to all the items in the group
          map(item => ({ ...item, streetName })),
        ))
      );
  })
).subscribe(items => {
  console.log(items); //now all the items have the street name
});

https://stackblitz.com/edit/rxjs-merge-providers?file=index.ts

相关问题