简体   繁体   中英

Angular async promise is not chaining correctly to give back 1st call in order to make 2nd call

I want to return a zipcode before I call a 2nd service, so that -- from what I thought I know -- I can wrap in a promise, and then ask for the promise later. So I figured I would just place my 2nd service inside the promise of the 1st service. But chaining promises this way is not being friendly.

Angular factory is called up and inside the factory method:

var userGeoPromise = userService.getGeoposition().then(function (geoposition) {
    vm.geoposition = geoposition;
            return addressService.reverseGeocode(geoposition.coords);
    }).then(function (data) {
            vm.currentLocation = googleService.googleAddressComponentsToAddress(data.results[0]);
            zipCodeCurrent = vm.currentLocation.zip;
    });

Notice 2 things above:

  1. I assigned the promise to var userGeoPromise
  2. zipCodeCurrent is set which contains the zipcode

Promise Testing works fine:

userGeoPromise.then( function() {
      console.log('should always show', zipCodeCurrent);
});

2nd service call:

userGeoPromise.then( function() {
     var serviceBase = "http://localhost:2295/api/getservicezip/"+ zipCodeCurrent;
     var serviceZipPromise = $http.get(serviceBase);
     return serviceZipPromise.then(function (results) {
          console.log('serviceZipPromise', results);
          return results.data;
     });
});

But now the site modal just spins when I put the serviceZipPromise.then ... inside the other promise.

Switch the order and add in 2 separate error handlers ( which is a good practice btw)

  var serviceZipPromise = $http.get(serviceBase);  // call up 
        return serviceZipPromise.then(function (results) {
            console.log('should always show', zipCodeCurrent);
            userGeoPromise.then(function () {
                //console.log('serviceZipPromise', results);
                console.log('inside servicezip ', zipCodeCurrent);

            }, function (err) {  // error from userGeoPromise
                console.log(err);
            });

             return results.data;  // THIS will return the data
        }, function (err) { // outer error,  this was switched 
            console.log(err);

        });

This should not error, but for your real serviceBase to end up using the zip code, u might have to execute it a bit later

UPDATE answer for you

  // created part of the api call
  var xserviceBase = "http://localhost:2295";  // this looks to be your base

  return userGeoPromise.then(function(){
       return $http.get(xserviceBase + '/api/getserviceablezip/' + zipCodeCurrent).then(function(results){
             return results.data;
       })
  });

Yes, I know that the 3 returns look a bit nasty, but it should work

In a then callback you should return the result value, not assign it to zipCodeCurrent (or any other variable). You did this correctly in the first then callback, but you should apply the same principle in the second:

var userGeoPromise = userService.getGeoposition().then(function (geoposition) {
    vm.geoposition = geoposition;
    return addressService.reverseGeocode(geoposition.coords);
}).then(function (data) {
    vm.currentLocation = googleService.googleAddressComponentsToAddress(data.results[0]);
    return vm.currentLocation.zip; // *** return it
});

NB: I did not touch the assignments to the properties of vm , but normally you should avoid mutating variables which (apparently) exist outside of the scope of these callback functions.

The Promise test would look like this:

userGeoPromise.then( function(zipCodeCurrent) { // *** add the argument
    console.log('should always show', zipCodeCurrent);
});

The 2 nd service has a nested then call, which is something to avoid. Instead of calling a then on a nested, intermediate promise, return that promise, and apply the then on the main promise chain:

userGeoPromise.then( function(zipCodeCurrent) { // *** add the argument as in the test
    var serviceBase = "http://localhost:2295/api/getservicezip/"+ zipCodeCurrent;
    return $http.get(serviceBase); // *** return the promise
}).then( function (results) { // *** move the then-callback to the outer chain
    console.log('serviceZipPromise', results);
    return results.data;
}).catch( function (error) { // *** add error handling at the end of the chain
    console.log('error occurred:', error);
});

Note how the nesting level is never more than 1.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM