【问题标题】:How to simplify nested ajax subscribe call for Angular 6如何简化 Angular 6 的嵌套 ajax 订阅调用
【发布时间】:2019-03-26 04:23:27
【问题描述】:
getBudgetMap(budgetMonthID){
        this.rows = [];
        this.categoryService.getCategory(budgetMonthID).subscribe(category =>{
            this.categoryList = category;
            this.categoryList.forEach(category => {

                this.transactionService.getTransaction(budgetMonthID, category.id).subscribe(transaction => {
                    this.rows = this.rows.concat(transaction);
                })

            })
        )
    }

为了简单起见,我有一个嵌套的 ajax 服务 (http.get) 调用,第一个调用 (getCategory) 返回基于 budgetMonthID 的类别列表。类别的数量各不相同。然后每个类别将进行第二次调用getTransaction 以检索属于每个类别的所有事务。上面的代码运行良好,但我一直在阅读关于 AngularmapflapMappipe,我只是不知道如何更改那个讨厌的代码。谢谢

【问题讨论】:

  • 您使用的是哪个 DBMS?
  • 我相信你会得到很好的答案,但我认为你现在拥有的这段代码远非“讨厌”(除了巨大的缩进 :)),而且可能更容易不惜一切代价阅读/维护而不是使用 RxJS 运算符。只是我的 2 美分。

标签: angular dictionary pipe subscribe flatmap


【解决方案1】:

您可以使用处理异步调用的rxjs operators。要变得珍贵,您应该使用switchmapflatmapmergemap。可以给出代码,但是您将来会再次遇到相同的问题。所以我鼓励你有时花些时间来了解 rxjs 操作符是如何工作的。

请通过这个 - https://www.learnrxjs.io/operators/transformation/switchmap.html

【讨论】:

  • 最好学习默认使用mergeMap,而不是switchMap,因为后者如果使用不当会导致'dataloss'
【解决方案2】:

这确实需要一些 rxjs 知识。

this.categoryService.getCategory(budgetMonthID).pipe(
  tap((categories) => this.categoryList = categories),
  mergeMap((categories) => zip(
    ...categories.map(
      (category) => this.transactionService.getTransaction(budgetMonthID, category.id)
    )
  )
).subscribe((rows) => {
  this.rows = rows;
});

首先,我们使用tap 将类别保存到categoryList。这是一个只执行函数但对管道流没有影响的运算符。

之后,我们使用mergeMap 提取类别,并返回另一个 Observable。在这种情况下,zip,它会等待所有参数完成,然后再以数组的形式发出,订阅将获取该数组。

您也可以尝试从 Angular 查看内置的async 管道。这消除了在组件内部取消订阅的需要,并保持其清洁。这会将您的代码更改为:

this.categoryList$ = this.categoryService.getCategory(budgetMonthID).pipe(
  shareReplay(1)
);

this.rows$ = this.categoryList$.pipe(
  mergeMap((categories) => zip(
    ...categories.map(
      (category) => this.transactionService.getTransaction(budgetMonthID, category.id)
    )
  )
);

在您的模板中,您可以像这样访问它:

<div *ngFor="let category of categoryList$ | async"></div>
<div *ngFor="let row of rows$ | async"></div>

【讨论】:

  • 应该是this.categoryList = categoriesswitchMap 也不会更适合这里吗?仍然不完全熟悉 RxJS,但您似乎不再需要使用初始 observable 的值。
  • @Jeto 未经测试的代码确实 :) 改变了类别。不,您应该尝试仅在有意义的情况下使用 switchMap。请参阅我对 SunilSingh 回答的评论
  • 使用 switchMap,只有在有充分理由的情况下才使用 mergeMap!
  • @Jeto 不客气。不过你是对的,我只能假设这些是立即完成的 ajax 请求,这使得 concatMap/mergeMap/switchMap 都具有相同的结果,但我个人更喜欢 concatMap 这里,因为你真的等待它完成并描述代码更彻底,但意见不同
猜你喜欢
  • 1970-01-01
  • 2019-02-12
  • 2019-12-24
  • 1970-01-01
  • 2021-11-18
  • 2020-12-09
  • 2019-08-05
  • 2022-08-25
  • 1970-01-01
相关资源
最近更新 更多