【问题标题】:RxJS in combining http requests during component initialization in Angular 2+RxJS 在 Angular 2+ 中的组件初始化期间组合 http 请求
【发布时间】:2018-08-22 01:06:51
【问题描述】:

我有一个问题。我是 RxJS 的初学者,还没有找到答案网络。因此,想请教您。 我需要什么:我从 ActivatedRoute 中提取一个 Id,然后(在我看来,但不确定)创建 2 个流。第 1 - 将下载项目的相关部分,第 2 - 将下载主要详细信息。下一个请求取决于此详细信息。
我用下面的代码执行这个逻辑。一切正常。但是,恐怕我写的代码不应该是好的。也许有人可以纠正我并解释我的错误。我有一些直截了当的问题,我把它放在这里并在代码中用数字标记以便于导航。

1) 当我创建 2 个单独的流时,它会启动 router$ 两次。那很重要么?我怎样才能启动它一次,然后在 2 个流上分开?

2) forkJoin。实际上我不需要等到所有请求都被执行。我没有找到合适的运算符,它会在不等待另一个值的情况下发出值。如果任何请求的错误都不会取消所有其他请求,那就太好了。还有其他合适的运营商吗?

3) switchMap 还是 mergeMap?我知道 switchMap 取消了之前的请求,但我仍然不知道哪个运算符更适合它。

4) 我最后决定将其合并为 1 个订阅并在 ngOnDestroy 中取消订阅。但也许使用 subscribe 而不是 operator map 并分别取消订阅会更好?

提前感谢您的回答。如果您有任何其他想法或意见,请拍摄。我会很感激的!

router$ =  this.aRoute.paramMap.map(params => +params.get('id'));        // <----  1

ngOnInit() {
  this.details$ = this.router$.mergeMap(id => {                           // <---- 3
    return this.claimSvc.getClaimDetails(id);
  }).do(details => {
    this.currentDetails = details;
    .... // some borring things            
  }).switchMap(details => {                                              // <---- 3
    return  Observable.forkJoin(                                          // <--- 2
      this.claimSvc.getDocuments(details.date....),
      this.claimSvc.getHolders(details.date...),
      this.claimSvc.getSubTypes(details.date...),
      this.claimSvc.getCategories(details.date...)
    )
  }).map(([documents, holders, subtypes, categories]) => {
    this.documents = documents;
    this.holders = holders;
    this.subTypes = subtypes;
    this.categories = categories;
  });

  this.claimParts$ = this.router$.switchMap(id => {                     // <---- 3
    return Observable.forkJoin(                                         //  < ------ 2
      this.claimSvc.getAttributes(id), 
      this.claimSvc.getParties(id),
      this.claimSvc.getClaimObjects(id),
      this.claimSvc.getClaimInsurances(id),
      this.claimSvc.getClaimPayments(id)
    )
  }).map(([Attribute, Parties, Objects, Insurances, Payments]) => {
    this.attributes = Attribute;
    this.parties = Parties;
    this.objects = Objects;
    this.insurances = Insurances;
    this.payments = Payments;
  });

  this.subscription = Observable.merge(this.claimParts$, this.claimDetails$).subscribe();  // <----  4
}

【问题讨论】:

    标签: angular typescript rxjs observable rxjs5


    【解决方案1】:
    1. 创建警卫
    2. 内部守卫,有 2 个函数,每个函数触发一个请求并从中返回 Observable
    3. 在守卫CanActivate 方法中执行以下操作:

    .

    FireFirstRequest(): Observable<boolean> {
    ///get your data and save it somewhere (shared service or something)
    ///and return Observable<boolean> (true) when done
    }
    
    FireSecondRequest(): Observable<boolean> {
    ///get your data and save it somewhere (shared service or something)
    ///and return Observable<boolean> (true) when done
    }
    
    canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
       const combined = Observable.zip(
       this.FireFirstRequest(),
       this.FireSecondRequest(),
       (a, b) => a && b
       );
    
       return combined;
    }
    
    1. 在路由定义中,使用防护来保护该路由/组件

    Observable.zip 确保仅当每个内部 Observable 都已发送并且它们都是 true (a&amp;&amp;b) 时才返回 true

    【讨论】:

    • 谢谢@dee zg,所以你建议如果组件没有获取数据就不要打开它?我可以像在组件中一样从 Guard 中的参数中提取 id 吗?
    • 好吧,如果组件在创建实例之前需要一些数据,那么是的,它不应该在你有数据之前打开。是的,您可以在警卫中提取任何路线数据。只需在警卫中注入 activeRouteSnapshot。
    • hm,但实际上每个路由导航和组件交换都从服务器请求一些数据。这是否意味着应用程序中的所有导航都应该使用 CanActivate guard 或 Resolve 完成?
    • 是的,我就是这么做的。这取决于您的用例,取决于您是否缓存数据,是否区分第一个和随后的组件打开...但通常是的,我的默认方法是在 canactivate/resolver 中获取数据,然后如果有一些特殊情况我偏离那个。
    猜你喜欢
    • 2018-11-23
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 2021-06-14
    • 2017-12-07
    • 2022-01-25
    • 1970-01-01
    • 2016-04-17
    相关资源
    最近更新 更多