代码之家  ›  专栏  ›  技术社区  ›  Michael

HTTP服务在参数初始化之前启动

  •  0
  • Michael  · 技术社区  · 4 年前

    我在项目中使用了角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 get作为参数communetyid,communetyid在if语句中获取值。由于异步 dataService.getCommunityById 函数在communityid获取值之前触发,我在控制台中收到错误。

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

    我知道我可以复制 dataService.getCommunityById 内部订阅 dataService.getCode 但我想防止代码重复。

    0 回复  |  直到 4 年前
        1
  •  1
  •   Tomov Nenad    4 年前

    如果你想保持你使用的原始模式(嵌套订阅),你应该把“getCommunityById”http调用移动到“dataService.getCode”回调中,它就会起作用。这里的关键是要理解“dataService.getCode”将返回一个可观测值(不存在的数据),而你的else分支使用已经存在的值(params.id)。 解决这个问题的正确方法是在管道()中使用concatMap()并链接这些操作。在concatMap()回调函数中,您将处理if-else分支逻辑,在那里您将返回this.daService.getCode或Observable.of(params.id),然后在下一个concatMap。

        2
  •  1
  •   Owen Kelvin    4 年前

    你可以考虑将你的 Observables 使用更高阶 operators

    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")
        }))
      );
    

    我正在使用 paramMap 从中提取参数 ActivatedRoute 从Angular Docs中, params 已弃用(或即将弃用)

    激活的路由 包含两个性能不如其替代品的属性,在未来的Angular版本中可能会被弃用。

    下一步,我们定义一个属性 communityId 其值取决于映射 参数 通过检查 category 财产。我正在使用 mergeMap 操作员合并订阅 params$ communityId$ .

    最后的步骤是 community$ 在这里,我们使用 switchMap 。如果有新的请求,我们不想继续进行初始请求,因此此运算符在这里最合适

    See a sample demo

        3
  •  0
  •   Aakash Garg    4 年前

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

    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操作符将按顺序保存您的调用,我还修改了代码使其更短。

        4
  •  0
  •   Medhat Mahmoud    4 年前

    我想你可以用 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));
    
        5
  •  0
  •   Ram    4 年前

    尽管你可以使用rxjs来链接可观察对象。还有另一种简单的方法可以解决你的问题。如果你把任何东西放在可观察对象的订阅中,它就会被执行,所以你需要把它作为一个单独的函数移到外面。它应该能帮助你防止打电话给你的 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的另一种方法,这更容易理解。您还可以使用rxjs运算符,如 concatMap , 属于 正如所建议的 梅德哈特·马哈茂德 穆罕默德·坎·通布尔 .