.then of Promise.all result never executes

2019-07-25 05:10发布

问题:

I am trying to use Promise.all and map instead of the forEach loop so the task can be asynchronous. All of the promises in the Promise.all array get executed and are resolved. The code looks like this:

loadDistances() {
    //return new Promise((resolve, reject) => {
      let rrr;
      let arr = [];
      this.geolocation.getCurrentPosition().then((resp) => {            
          // resp.coords.latitude
          rrr = resp;
          console.log(rrr + "              rrrrrrrrrrrrrrrrrrrrrrrrrr");

          setTimeout(() => {
            this.distancelist = this.af.list('/profiles/stylists');

            let x = 0;
            this.subscription6 = this.distancelist.subscribe(items => {

              let mapped = items.map((item) => {
                return new Promise(resolve => {
                  let rr;
                  //console.log(JSON.stringify(item) + "               *((*&*&*&*&^&*&*&*(&*(&*&*(&(&(&*(              :::" + x);
                  if(item.address == "") {
                    /*if(!item.picURL) {
                      item.picURL = 'assets/blankprof.png';
                    }*/
                    //arr.push({'pic':item.picURL, 'salon':item.username, 'distance':"No Address"});
                    //x++;
                  }
                  else {
                    console.log(item.address + " is the address empty??????");
                    this.nativeGeocoder.forwardGeocode(item.address)
                      .then((coordinates: NativeGeocoderForwardResult) => {
                        console.log("I AM IN THE GEOCODING ***&&*&*&*&*");
                          rr = this.round(this.distance(coordinates.latitude, coordinates.longitude, rrr.coords.latitude, rrr.coords.longitude, "M"), 1);
                          if(!item.picURL) {
                            item.picURL = 'assets/blankprof.png';
                          }
                          arr.push({'pic':item.picURL, 'salon':item.username, 'distance':rr});
                          console.log("push to the array of results");
                          //x++;
                          /*console.log(items.length + "         length   /    x:        " + x);
                          if(items.length - x == 1) {
                            console.log("getting resolved in geocoder ^&^&^&&^^&^&^&");
                            resolve(arr);
                          }*/
                          resolve();
                        }).catch(e => {
                          console.log(e.message + " caught this error");
                          /*x++;
                          if(items.length - x == 1) {
                            resolve(arr);
                          }*/
                          resolve();
                        })
                  }

                })
              });

              let results = Promise.all(mapped);
              results.then(() => {
                console.log(JSON.stringify(arr) + " :FOSIEJO:SFJ::EFIJSEFIJS:EFJS:IO THIS IODIOSJ:FDSIJ :DIS");
                arr.sort(function(a,b) {
                  return a.distance - b.distance;
                });

                this.distances = arr.slice();
              })

            });//);
          }, 1500)




      /*}).catch((error) => {
        this.diagnostic.switchToLocationSettings();
        console.log('Error getting location', error.message);
        resolve();
      });*/

    });


  }

The console output is:

[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:27]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:27]  console.log: push to the array of results 
[12:38:28]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:28]  console.log: push to the array of results 
[12:38:29]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:29]  console.log: push to the array of results 
[12:38:29]  console.log: I AM IN THE GEOCODING ***&&*&*&*&* 
[12:38:29]  console.log: push to the array of results 

The alternating messages make it seem like it worked and all of the promises got resolved. But when I do Promise.all this line never happens in the console:

console.log(JSON.stringify(arr) + " :FOSIEJO:SFJ::EFIJSEFIJS:EFJS:IO THIS IODIOSJ:FDSIJ :DIS");

So it is not reaching the then of the Promise.all results.

回答1:

You have code paths that don't resolve, specifically:

if(item.address == "") {
  /*if(!item.picURL) {
    item.picURL = 'assets/blankprof.png';
  }*/
  //arr.push({'pic':item.picURL, 'salon':item.username, 'distance':"No Address"});
  //x++;
}


回答2:

It is very easy getting into deadlocks like @andy-gaskell pointed out when creating new Promises. To avoid that you better do one of these; All of these may throw an impossible error or return 1.

function promiseWithTryCatch() {
  return new Promise((resolve, reject) => {
    try {
      let result;
      // your code

      resolve(result);
    }
    catch(ex) {
      reject(ex);
    }
  })
}

function promiseWithResolve() {
  return Promise.resolve()
    .then(() => {
      let result;
      // your code

      return result; 
    })
}

async function promiseWithAsync() {
  let result;
  // your code

  return result;
}

Replace the comment with your code and place the ending result into the variable result. If your code contains async code, you better make a new function with the same pattern and return that as the result, eg: result = [promise method]

  • The most scary one is "new Promise", if any code does not resolve or reject it will end in a "dead-lock", that's why it is important to have a try/catch.
  • If you are using Promise.resolve() it will catch any errors inside .then but don't do any code outside .then, otherwise you have to catch exception and return a Promise.reject(new Error())
  • The safest is async function, since any "throw" will return a Promise.reject, and "return" will return a Promise.resolve

Play around with this example, but I had to comment out async/await since this snippet tool doesn't handle ES2016.

function nestedPromise(num) {
  return Promise.resolve(' myNestedValue is ' + num);
}

function promiseWithTryCatch() {
  return new Promise((resolve, reject) => {
    try {
      let mynumber = 2 + 5;

      nestedPromise(mynumber)
        .then((answer) => {
          resolve(answer.trim());
        })
        .catch(ex => {
          // error handling for async-code
          reject(ex);
        })
    }
    catch(ex) {
      // error handling for sync-code
      reject(ex);
    }
  })
}

function promiseWithResolve() {
  return Promise.resolve()
    .then(() => {
      let mynumber = 2 + 5;

      return nestedPromise(mynumber);
    })
    .then((answer) => {
      // do something with the answer
      return answer.trim();
    })
}

/*
async function promiseWithAsync() {
  let mynumber = 2 + 5;
  let answer = await nestedPromise(mynumber);
  
  return answer.trim();
}
*/

promiseWithTryCatch()
  .then(answer => console.log('promiseWithTryCatch result is ' + answer))
   .catch(err => console.log('promiseWithAsync error is ' + err.message));
   
promiseWithResolve()
  .then(answer => console.log('promiseWithResolve result is ' + answer))
  .catch(err => console.log('promiseWithResolve error is ' + err.message));

/*
promiseWithAsync()
  .then(answer => console.log('promiseWithAsync result is' + answer))
  .catch(err => console.log('promiseWithAsync error is ' + err.message));
*/