代码之家  ›  专栏  ›  技术社区  ›  Ayoub.A

Javascript:嵌套承诺太多

  •  -2
  • Ayoub.A  · 技术社区  · 6 年前

    我用的是角度 HttpClient 在服务器中存储一些数据,但我只能重复一条指令。保存过程如下:

    if(client is new){
      //promise starts
      store client and retrieve id
    
    
      if(client has companion){
        //promise starts
        store companion and retrieve id
    
        //promise starts
        store product with previous retrieved id
      }
      //promise starts
      store product with only client id
    
    }else{
      //promise starts
      store product 
    }
    

    正如您所看到的,“存储产品”说明重复了三次,因为在继续之前,我需要从服务器返回信息。 以下是实际代码:

    //Check if the client is new
        if (this.rent.client.id === 0) {
    
          this.clientServce.saveClientToDatabase(this.rent.client)
            .subscribe((results) => {
              //Store the new client Id
              this.rent.client.id = results.clientID;
    
              //Check if companion exists and save it to database
              if (this.rent.companion.id !== -1) {
                this.clientServce.saveCompanionToDatabase(this.rent.companion)
                  .subscribe((companionResults) => {
                    this.rent.companion.id = companionResults.clientID;
    
                    //Save te rent
                    this.rentServices.saveRentToDatabase(this.rent).subscribe()
                  })
              } else {
                //Save te rent
                this.rentServices.saveRentToDatabase(this.rent).subscribe();
              }
            })
        } else {
          //Save te rent
          this.rentServices.saveRentToDatabase(this.rent).subscribe();
    
        }
    

    它看起来确实可读。那么,如何才能管理客户机和同伴,最终以可读的方式存储和存储产品呢?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Tomasz Kula    6 年前

    嵌套订阅块是一种反模式。您的代码很容易受到多种竞争条件的影响。您正在处理http调用之间的内部服务状态。这意味着如果有多个调用激发到 saveClientToDatabase 很快,其中一些可能会以错误数据告终。

    请尝试以下操作:

    import { mergeMap } from 'rxjs/operators';
    import { of } from 'rxjs/observable/of';
    import { forkJoin } from 'rxjs/observable/forkJoin';
    
    const hasCompanion = this.rent.companion.id !== -1;
    const rent = this.rent;
    
    const saveClient$ = this.clientService.saveClientToDatabase(rent.client);
    const saveCompanion$ = hasCompanion ? this.clientService.saveCompanionToDatabase(rent.companion) : of(null);
    
    const saveRent$ = forkJoin([saveClient$, saveCompanion$]).pipe(mergeMap(([client, companion]: [any, any]) => {
      return this.rentServices.saveRentToDatabase(companion ? {
         ...rent,
         clientID: client.clientID,
         companion: companion.companionID
       } : {
         ...rent,
         clientID: client.clientID,
       })
    }));
    
    // single subscription and single manipulation of the internal state
    saveRent$.subscribe(rent => this.rent = rent);