Angular7中如何处理嵌套的HTTP请求?

How to handle nested HTTP requests in Angular 7?

我有一个从服务器获取数据的通用服务。收到响应后,我使用映射器函数将纯 JSON 数据映射到所需模型。对于某些 class 类型的映射器函数,我需要从服务器获取一些额外的数据。如何强制映射器函数等待第二个请求?

这是我的获取函数:

 getChildren(params: ITreeQueryParams): Observable<Optional<T[]>> {
    params.id = isPresent(params.id) ? params.id : 0;
    params.parentId = isPresent(params.parentId) ? params.parentId : 0;
    params.isRoot = isPresent(params.isRoot) ? params.isRoot : false;
    params.additionalId = isPresent(params.additionalId) ? 
    params.additionalId : 0;
    return this.http.get<IListResponse<T>>
(`${this.resourceUrl}/getChildren/${params.id}/${params.parentId}/${params.isRoot}/${params.additionalId}`,
      {
        observe: 'response'
      }).pipe(map((resp) => this.mapResponse(resp,this.model)));
  }

这是我的映射函数:

 protected mapResponse(resp: any, model: IAsset): void {
    if (resp) {
      this.anotherTreeService.getNodeDetail(resp.id, resp.isRoot).subscribe(res => {
        model.additionalData = {canEdit: res.length > 0 ? true : false};
      });
      if (resp.name) {
        model.title = resp.name;
      }
    }
  }

如果我对你的理解是正确的,你只是想提出一个请求并为它提出子请求。

为此,如果您需要接受许多子请求,您可以使用 switchMapforkJoin

这是重写代码的方法(我会写一个简化版本)

getChildren() {
  this.http.someRequest.pipe(
    tap(response => {
        if (resp.name) {
          model.title = resp.name;
        }
    }),
    switchMap(response =>
        forkJoin(
            response.map(r => this.http.someRequest(r))
        )
    )
  )
}

switchMap 所做的是在每次源发射(您的第一个可观察对象)之后,它订阅回调中返回的可观察对象(如果它已经被订阅,它首先取消订阅回调可观察对象)。

forkJoin 的工作方式类似于 Promise.all。您可以向那里传递一个数组、对象或多个可观察对象(现已弃用),在订阅中您将获得一个数组或一个对象。

请注意 forkJoin 仅当所有可观察对象完成时 才会发出每个可观察对象发出的最后一个值 。此外,如果任何 observable 完成而没有发射值 forkJoin 也完成而没有发射值。由于所有 http.whatever 都是一个 next 和立即 complete 之后的可观察对象,因此您不必担心这一点。

此外,如果有任何可观察到的错误 forkJoin 错误。

RxJS 中有很多运算符可以实现您想要的。当数据模型本身不包含所有数据并且您需要单独调用以根据第一个结果检索其他数据时,您经常看到的是这样的示例:

this.myFirstService.getById(id).pipe(
   map(data => jsonToMyModel(data)),
   tap(model => this.data = model),
   switchMap(model => {
      return this.mySecondService.getListById(model.id)
   }),
   tap(secondData => this.data.list = secondData)
).subscribe()

这改变了您真正想要实现的目标,因为可以通过使用 forkJoin()mergeMap() 使所有数据最终都在 Observable 返回的一个模型中。这些运算符中的任何一个在这些类型的情况下都有其用途。

希望这对您有所帮助。一个更清楚和直接的例子,你想要什么需要一个更完整的问题,用一些例子来说明你想要什么和你已经尝试过什么。