Search code examples
angularrxjsobservablees6-promise

Watch for Promise completion, then exec next Promise. Observable vs Promise?


Basically I have calls to different SQL stored procedures that return Promises. Normally these would begin/end in random orders since they are asynchronous. I need to control the order each procedure is called.

I have tried using .then() on the callCustomerIUD promise, but this._dataService.customerIUD(...).then(...) doesn't run until after callCustFieldIUD(), so customerFieldIUD gets this.key as undefined.

saveChanges(record) {
   this.callCustomerIUD(record);
   this.callCustFieldIUD();
}

callCustomerIUD(record): Promise<any>{
   return this._dataService
        .customerIUD(...)
        .then(data => {
            //THIS KEY IS NEEDED FOR customerFieldIUD
            this.key = data[data.length-1].CustomerKey; 
        }, error => {
            console.log(error);
        });
}

callCustFieldIUD() : Promise<any>{
    //USES KEY FROM customerIUD
    this.fillCustomerField(this.key);
    return this._dataService.customerFieldIUD(...);
}

I have considered Observables, can I use them in this case? Here is my data.service.ts methods reference above. Should these be Observables and not Promises?

customerIUD(data: any) : Promise<any>{
    return this.fooHttp
        .postData(...);
}

customerFieldIUD(data: any) : Promise<any>{
    return this.fooHttp
        .postData(...);
}

Solution

  • Yes, observables would be great in this scenario

    saveChanges(record) {
       this.callCustomerIUD(record).take(1).subscribe((data: any) => {
         // Observables can be subscribed to, like a .then() on a promise
         // data will be the response from the http call
         this.callCustFieldIUD(data).take(1).subscribe();
       });
    }
    
    callCustomerIUD(record): Observable<any>{
       return this._dataService.customerIUD(...)
    }
    
    callCustFieldIUD(data: any) : Observable<any>{
        //USES KEY FROM customerIUD
        this.fillCustomerField(this.key);
        return this._dataService.customerFieldIUD(...);
    }
    

    And in the service

    customerIUD(data: any) : Observable<any>{
      return this.fooHttp.postData(...).map((res: any) => {
        return res.json();
      });
    }
    
    customerFieldIUD(data: any) : Observable<any>{
      return this.fooHttp.postData(...).map((res: any) => {
        return res.json();
      });
    }
    

    because the callCustFieldIUD() function is being called inside of the subscribe() to the observable returned by the callCustomerIUD() function, it won't execute until the data is there.

    (This may not be the exact code you need. I'm not sure what has to happen when, but by subscribing to observables, you can be more strict about when functions get called)

    Hope this helps

    _______________ EDIT _________________________

    I believe you can achieve this with promises too, just needs a slight refactor

    saveChanges(record) {
       this.callCustomerIUD(record);
    }
    
    callCustomerIUD(record): Promise<any>{
       return this._dataService
            .customerIUD(...)
            .then(data => {
                // Instead of setting an instance var here, pass it in to the callCustFieldIUD() function
                this.callCustFieldIUD(data[data.length-1].CustomerKey);
            }, error => {
                console.log(error);
            });
    }
    
    callCustFieldIUD(customerKey: any) : Promise<any>{
        //USES KEY FROM customerIUD
        this.fillCustomerField(this.key);
        return this._dataService.customerFieldIUD(...);
    }