代码之家  ›  专栏  ›  技术社区  ›  Ari Roth

使一种方法取决于另一种方法的成功运行

  •  0
  • Ari Roth  · 技术社区  · 6 年前

    在我执行HTTP调用之前,我需要一个服务设置几个字段。这些字段来自另一个HTTP调用,因此我无法异步运行它们——如果没有这些数据,第二个调用将失败。我想我有办法做到这一点,但我遗漏了一些东西——第一种方法( getSystemConfiguration() )只是没有开火,即使在链条的末端肯定有一个 subscribe() 呼叫

    我对RxJs有些陌生,所以我觉得这应该很简单,但我缺少什么呢?

    // Method that gets system configuration
    setApiInformation(): Observable<void> {
        if (!this.apiKey || !this.checkUrl) {
            return this.systemConfigurationService.getSystemConfiguration()
                .pipe(
                    map(config => {
    
                    // None of this ever executes
                    this.apiKey = config.apiKey;
                    this.checkUrl = config.objectExistsUrl;
                }));
        } else {
            return of();
        }
    }
    
    // Method I'm trying to run
    checkServerData(data: RequestParameters): Observable<ServerResponseData> {
        return this.setApiInformation()
            .pipe(map(() => {
                let httpOptions = { headers: new HttpHeaders({ "serverApiKey" : this.apiKey }) };
                return this.httpClient.put<ServerResponseData>(this.checkUrl, request, this.httpOptions);
            }));
    }
    
    // Ultimate caller
    let params: RequestParameters = { tenantId: 1, requestorId: 1 };
    this.service.checkServerData(params)
       .subscribe((response: ServerResponseData) => { this.dataExists = response.success; });
    
    0 回复  |  直到 6 年前
        1
  •  1
  •   pouya zad    6 年前

    几乎没有 rxjs 操作员可以帮你解决这个问题。我个人更喜欢 switchMap .我将这样实施:

    this.setApiInformation().pipe(switchMap(data => {
      // do something here if needed
      return this.checkServerData();
    })).subscribe( data => {
      // do something
    });
    
        2
  •  1
  •   bryan60    6 年前

    这里有几件事。首先,你的可观察链有问题,你通常希望把事情保持在可观察序列内,并且你希望以可重复的方式来做这件事。我可以这样重写:

    interface Config {
      apiKey: string
      checkUrl: string
    }
    
    @Injectable()    
    export class MyService {
      private configSource = new ReplaySubject<Config>(1) // stores config
    
      private setApiInformation() { // private method to load config, call once
        this.systemConfigurationService.getSystemConfiguration().subscribe(this.configSource)
      }
    
      // all calls go through here to ensure config is ready
      private awaitConfig<T>(action$: (config: Config) => Observable<T>) {
        return this.configSource.pipe(
          first(),
          switchMap(client => action$(client)) // switchMap subscribes to inner observables
        )
      }
    
      constructor(private systemConfigurationService: SystemConfigurationService) {
        this.setApiInformation() // call once here
      }
    
      checkServerData(data: RequestParameters): Observable<ServerResponseData> {
        return this.awaitConfig(config => { // use config from here
          let httpOptions = { headers: new HttpHeaders({ "serverApiKey" : config.apiKey }) };
          return this.httpClient.put<ServerResponseData>(config.checkUrl, request, this.httpOptions);
        }));
      }
    }
    

    这是解决所有调用都需要异步的问题的一个好方法,理论上,你可以编写一个基础服务,其他调用可以从中扩展,或者最好是注入并使用它来进行调用,但是,如果这是应用程序范围内的事情,那么最好使用app_初始化器来确保在应用程序的其余部分运行之前完成一些事情(liek加载配置)。