calling a promise within a promise , with $q.all [

2019-09-14 03:21发布

问题:

This question already has an answer here:

  • multiple promises running in parallel, $q.all needs chaining? 1 answer

I have multiple api requests which can run in parallel.

getlocations, getstates, get territories can make a request in parallel. however once i have the states list from getstates() call, i need to make an api request for each individual state and parse the state object.

Here is the code that i have so far, Is it ok to call a promise within a promise this way ?

  getAllLocations() {
    //make a promise call for all here .
    var promise = [];
    //first prmise
    promise.push(this.getAllLocations(Id).then(
        (locationsData) => {
            this.locations = locationsData;
        }));
    //second promise
    promise.push(this.getAllStates(Id).then(
        (resp) => {
            this.states = resp.data;
            //for each state , need to make an api call and add to the state info
            angular.forEach(this.states, function(state){
                var nodeId = state.Id;
                this.getStateSummary(nodeId).then((resp) => {
                    state.healthStatus = resp.data.operationalStatus;
                });
            },this)
        }));
    //third promise
    promise.push(this.getAllterritories(Id).then(
        (resp) => {
            this.territories = resp.data;
        }));
    //after all promises parse teh location data
    $q.all(promise).then(() => {
        for (var i = 0; i < this.locations.length; i++) {
            //do something with with location here
        }
        this.gridData = this.locations;
    });
}

if not , whats the best way to make teh getStatesummary() call ?

回答1:

I'd simplify each of the 3 promises (especially 1 and 3), so that this.locations, this.states and this.territories are all updated in the $q.all .then - you don't have to, but I think it makes the code a little more readable

Next, assign all 3 promises to a variable (p1, p2, p3 in the code below)

The next issue is waiting on all the states API calls to complete - another $q.all required there

All up, with a little extra ES6 goodness, you get

getAllLocations() {
    //first prmise
    const p1 = this.getAllLocations(Id);
    //second promise
    const p2 = this.getAllStates(Id).then(resp => 
        //for each state , need to make an api call and add to the state info
        $q.all(resp.map(state => this.getStateSummary(state.Id).then(resp => state.healthStatus = resp.data.operationalStatus)))
        .then(() => resp) // so we return data for this.states
    );
    //third promise
    const p3 = this.getAllterritories(Id).then(resp => resp.data);
    //after all promises parse teh location data
    $q.all([p1, p2, p3]).then(([locations, states, territories]) => {
        this.locations = locations;
        this.states = states;
        this.territories = territories;
        for (var i = 0; i < locations.length; i++) {
            //do something with with location here
        }
        this.gridData = this.locations;
    });
}

If the getAllStates promise returns a Object instead of my assumption that it's an array - then replace the inner $q.all with

        $q.all(Object.entries(resp).map(([key, state]) => this.getStateSummary(state.Id).then(resp => state.healthStatus = resp.data.operationalStatus)))

Actually, the above code would work for Array or Object equally :p



回答2:

you can use promise chain to send catch promises one after the another

 getAllLocations() {
     //make a promise call for all here .
     var promise = [];
     //first prmise
     this.getAllLocations(Id)
         .then(
             (locationsData) => {
                 this.locations = locationsData;
                 promise.push(this.locations);

                 return this.getAllStates(Id)
             }).then(
             (resp) => {
                 this.states = resp;
                 //for each state , need to make an api call and add to the state info
                 angular.forEach(this.states, function(state) {
                     var nodeId = state.Id;
                     return this.getStateSummary(nodeId);
                 }, this)
                 return this.getAllterritories(Id);
             }).then((resp) => {
             state.healthStatus = resp.data.operationalStatus;
             promise.push(state.healthStatus);
         }).then(
             (resp) => {
                 this.territories = resp.data;
                 promise.push(this.territories);
                 this.callAll(promise)
             })
 }


 callAll(promise) {
     //after all promises parse teh location data
     this.$q.all(promise).then(() => {
         for (var i = 0; i < this.locations.length; i++) {
             //do something with with location here
         }
         this.gridData = this.locations;
     });
 }