【问题标题】:HTTP service fired before the parameter initialized在参数初始化之前触发的 HTTP 服务
【发布时间】:2021-02-26 15:53:18
【问题描述】:

我在我的项目中使用 angular 10。 我在 ngOnInit 函数中嵌套了 HTTP 调用,如下所示:

ngOnInit(): void  {
  
  let communetyid;
  
    this.route.data.subscribe(data => { 
      this.route.params.subscribe(params => { 
        
      if(data.category === "code")
      {
        this.dataService.getCode(params.code)
          .subscribe(resp => { communetyid = resp.results.communityId });
      }
      else  
      {
        communetyid = params.id
      }

      this.dataService.getCommunityById(communetyid)
        .subscribe(response => { this.community = response.results; 
        
            ///other http calls
        
       }) 
     })
   })
})

正如您在上面的代码中看到的,dataService.getCommunityById 作为参数 communetyid 获取,communetyid 在 if 语句中获取值。由于在 communityid 获取值之前触发了异步 dataService.getCommunityById 函数,我在控制台中收到错误。

如何更改代码,当dataService.getCommunityById 被触发时,值 communetyid 将被初始化。

我知道我可以在dataService.getCode 的订阅中复制dataService.getCommunityById,但我想防止代码重复。

【问题讨论】:

  • 您可以找到针对您的案例的详细解决方案以及通过 Http in this article 使用 RxJs 的常见示例

标签: angular typescript asynchronous rxjs


【解决方案1】:

将您的代码更改为以下内容:-

ngOnInit(): void  {
  
  let communetyid;
  
    this.route.data.subscribe(data => { 
      this.route.params.subscribe(params => { 
        
      const communityIdObs = date.category === 'code' ? this.dataService.getCode(params.code).pipe(map(resp => resp.results.communityId)) : of(params.id);
      communityIdObs.pipe(mergeMap(res => {
         return this.dataService.getCommunityById(communetyid);
      }).subscribe(response => { 
            this.community = response.results; 
            ///other http calls
      });
})

Mergemap 操作员将保持您的调用顺序,我还修改了代码以使其更短。

【讨论】:

    【解决方案2】:

    尽管你可以使用 rxjs 来链接 observables。还有另一种简单的方法可以解决您的问题。如果您将任何内容放入可观察对象的订阅中,它就会被执行,因此您需要将其作为单独的函数移到外面。它应该可以帮助您防止调用 dataService.getCommunityById 函数。

    ngOnInit(): void  {
    
    let communetyid;
    
    this.route.data.subscribe(data => { 
      this.route.params.subscribe(params => { 
        
      if(data.category === "code")
      {
        this.dataService.getCode(params.code)
          .subscribe((resp) => 
          { 
              communetyid = resp.results.communityId;
              getCommunityData(communetyid);
        });
      }
      else  
      {
        communetyid = params.id;
        getCommunityData(communetyid);
      }
    
      })
     })  
    })
    
    getCommunityData(communetyid) {
      this.dataService.getCommunityById(communetyid)
      .subscribe(response => { 
         this.community = response.results;
         //other http calls
      })
    }
    

    这是使用 rxjs 的另一种方法,只是更容易理解。您还可以按照 Medhat MahmoudMuhammet Can TONBUL 的建议使用 rxjs 运算符,例如 concatMapof。。 p>

    【讨论】:

      【解决方案3】:

      您可以考虑使用更高阶的operators 链接您的Observables

      export class ChildComponent implements OnInit {
        constructor(
          private route: ActivatedRoute,
          private dataService: DataService
        ) {}
      
        // Extract Parameters from the Activated Route
        params$ = this.route.paramMap.pipe(
          map(params => ({
            id: params.get("id"),
            code: params.get("code"),
            category: params.get("category")
          }))
        );
      
        // Get Community Id
        communityId$ = this.params$.pipe(
          mergeMap(({ category, code, id }) =>
            category === "code"
              ? this.dataService
                  .getCode(code)
                  .pipe(map(({ results }) => results.communityId))
              : of(id)
          )
        );
      
        // Get Community
        community$ = this.communityId$.pipe(
          switchMap((communetyId) => this.dataService.getCommunityById(communetyId))
        )
      
        ngOnInit() {
          this.community$.subscribe({
            next: console.log
          });
        }
      }
      

      代码说明

      提取参数

        params$ = this.route.paramMap.pipe(
          map(params => ({
            id: params.get("id"),
            code: params.get("code"),
            category: params.get("category")
          }))
        );
      

      我正在使用paramMapActivatedRoute 中提取参数。从 Angular Docs,params 已弃用(或将被弃用)

      ActivatedRoute 包含两个性能不如其替代品的属性,并且可能在未来的 Angular 版本中被弃用。

      下一步我们定义一个属性communityId,其值取决于通过检查category 属性映射params。我正在使用mergeMap 运算符将params$ 的订阅合并到communityId$

      最后一步是获取community$。这里我们使用switchMap。如果已经发出新请求,我们不想继续初始请求,因此此运算符在这里最合适

      See a sample demo

      【讨论】:

      • 我认为只有当“code”是一个长度为 1 的字符串时才能按预期工作,如示例中所示。原因在于mergeMap 的使用方式。 mergeMap 想要一个返回 Observable 的函数作为参数。在建议的解决方案中,作为参数传递给mergeMap 的函数是{ category, code, id }) => category === "code" ? this.dataService.getCode(code).pipe(map(({ results }) => results.communityId)) : id,它返回一个可观察对象或一个字符串。但是一个字符串是一个 Observable,它会发出它的每个字符。如果您尝试使用带有“123”之类的code,您可以看到这一点。
      • @Picci 好观察,我已经更新了解决方案
      【解决方案4】:

      如果您想保留您使用的原始模式(嵌套订阅),您只需将“getCommunityById”http 调用移动到“dataService.getCode”回调中,它就会起作用。这里的关键点是要了解“dataService.getCode”将返回一个可观察的(不存在的数据),并且您的 else 分支使用已经存在的值(params.id)。 解决这个问题的正确方法是在 pipe() 中使用 concatMap() 并链接这些操作。在 concatMap() 回调中,您将处理 if-else 分支逻辑,您将在其中返回 this.dataService.getCode 或 Observable.of(params.id) ,然后在下一个 concatMap() 中,您将使用此值作为参数对于 this.dataService.getCommunityById。

      【讨论】:

      • 托莫夫,谢谢你的帖子。你能举个例子吗?
      【解决方案5】:

      我认为你可以使用concatMap 运算符

      要将一个响应转换为连续请求所需的参数,请使用concatMap

      操作员concatMap() 内部订阅了从其投影函数返回的 Observable 并等待它完成,同时重新发射其所有值。

      这是一个例子

      function mockHTTPRequest(url) {
          return Observable.of(`Response from ${url}`)
            .delay(1000);
      }
      
      let urls = ['url-1', 'url-2', 'url-3', 'url-4'];
      let start = (new Date()).getTime();
      
      Observable.from(urls)
        .concatMap(url => mockHTTPRequest(url))
        .timestamp()
        .map(stamp => [stamp.timestamp - start, stamp.value])
        .subscribe(val => console.log(val));
      

      【讨论】:

      • 请您提供一个与发布代码相关的示例。
      • concatMap 是在这种情况下使用的运算符。您可以阅读更多详情并找到类似案例的灵感in this article
      猜你喜欢
      • 2011-08-16
      • 1970-01-01
      • 2023-03-16
      • 2021-08-17
      • 1970-01-01
      • 1970-01-01
      • 2016-03-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多