如何在 Angular RxJS 中正确链接 concatMap

How to properly chain concatMaps in Angular RxJS

    this.route.params.pipe(
      concatMap((param) => {
        const ein = param['nonprofit-id'];
        return this.nonprofitService.getNonprofit(ein).pipe(
          concatMap((nonprofit) => {
            this.nonprofit = nonprofit;
            const ratingID = nonprofit.currentRating?.ratingID ? nonprofit.currentRating.ratingID : -1;
            return this.nonprofitService.getRatingForNonprofit(ein, ratingID).pipe(
              concatMap((nonprofitRating) => {
                this.nonprofitRating = nonprofitRating;
                const causeID = this.nonprofit?.cause?.causeID ? this.nonprofit?.cause?.causeID : 0;
                return this.nonprofitService.getSimilarNonprofits(causeID);
              })
            );
          })
        );
      })
    ).subscribe((response) => {
      this.similarNonprofits = response;
    });

我想知道以上是否是在 Angular RxJS 中链接 concatMap 的正确方法。其他两个调用依赖于检索到的相关“非营利组织”,以便返回其对象。 Rating 和 Similar Nonprofits 可以同时检索,所以我想有一些方法可以做到这一点,而无需将这些 concatMap 相互嵌套。

如果你需要使用所有以前的值,它通常以嵌套越来越多的链结束,但在这种情况下它似乎已经太复杂了所以你可以 map() 每个内部 Observable 到一个数组(或对象)中) 如下所示:

this.route.params.pipe(
  concatMap((param) => {
    const ein = param['nonprofit-id'];
    return this.nonprofitService.getNonprofit(ein).pipe(
      map(nonprofit => [ein, nonprofit]),
    );
  ),
  concatMap(([ein, nonprofit]) => {
    const ratingID = ...;
    this.nonprofitService.getRatingForNonprofit(ein, ratingID).pipe(
      map(nonprofitRating => [nonprofitRating, ein, nonprofit]),
    );
  }),
  concatMap(([nonprofitRating, ein, nonprofit]) => {
    const causeID = ...;
    return this.nonprofitService.getSimilarNonprofits(causeID).pipe(
      map(similar => [similar, nonprofitRating, ein, nonprofit]),
    );
  }
).subscribe(([similar, nonprofitRating, ein, nonprofit]) => { ... });

显然,您不必解包作为参数传递给连续 concatMap 的每个数组,但我希望您能明白这一点。

继续@martin 的回答,我建议使用 forkJoin 将最后两个 concatMap 合并为一个请求,因为它们不相互依赖。这也将并行触发请求,并可能有助于提高性能(虽然微不足道)。

我还用 nullish coalescing operator ?? 替换了三元运算符。

this.route.params.pipe(
  concatMap((param: any) => {
    const ein = param['nonprofit-id'];
    return this.nonprofitService.getNonprofit(ein).pipe(
      map((nonprofit) => ([ein, nonprofit]))
    );
  }),
  concatMap(([ein, nonprofit]) => 
    forkJoin([
      this.nonprofitService.getRatingForNonprofit(ein, (nonprofit.currentRating?.ratingID ?? -1)),
      this.nonprofitService.getSimilarNonprofits(ein, (this.nonprofit?.cause?.causeID ?? 0))
    ]).pipe(
      map(([nonprofitRating, similarNonprofits]) => ([
        nonprofit,
        nonprofitRating,
        similarNonprofits
      ]))
    )
  )
).subscribe({
  next: ([nonprofit, nonprofitRating, similarNonprofits]) => {
    this.nonprofit = nonprofit;
    this.nonprofitRating = nonprofitRating;
    this.similarNonprofits = similarNonprofits;
  },
  error: (error: any) => {
    // handle error
  }
});

您还可以定义一个具有属性的对象,以避免对多个元素使用解构语法。