3

I am using Google geocoding in my code. I have to geocode about 50 places, but Google doesn't allow to geocode so many places at the same time, generating a 'OVER_QUERY_LIMIT' error. So I want do delay the geocoding for few seconds when I exceed the quota. I have a function geocode() that returns a promise. When I exceed quota, I want to recursively call itself.

This is my not-working code:

function geocodeAll(addresses)
 {
   for (addr in addresses)
     {
      geocode(addresses[addr])
        .then(
              function(coord)
               {/* I don't always get here */}
             )
     }
 }


function geocode(address)
{
 var deferred = Q.defer();
 geocoder.geocode(address, function ( err, geoData ) 
        {
         if (err)
            { deferred.reject(err);}
         else
            {
             if (geoData.status=="OVER_QUERY_LIMIT" )
                 { // doh! quota exceeded, delay the promise
                  setTimeout(function()
                     {geocode(address)
                      .then(
                            function(coord)
                             {deferred.resolve(coord);}
                           );
                      }, 1000);
                    }
                else
                    { // everything ok
                     var coord = {'lat':geoData.lat, 'lng':geoData.lng};              
                     deferred.resolve(coord);
                    }
               }
      });

  return deferred.promise; 
}

UPDATE [solved]

actually the code is right. I had an uncaughtException not related to the delay. Using Q.all([..]).then().catch() I found it

DeLac
  • 1,068
  • 13
  • 43
  • Is your promise just never resolving, or are you getting an error? – bluetoft Feb 04 '16 at 23:49
  • I always get the result geocoded, but it is not returned back to the main function the called geocode() for the first time. – DeLac Feb 04 '16 at 23:51
  • You're not handling errors anywhere. How do you know you don't get one of them? – Bergi Feb 05 '16 at 12:42
  • How do you know that you always get the result when it's not returned back? – Bergi Feb 05 '16 at 12:43
  • 1
    Try to avoid the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572) and rather promisify `geocode` and `setTimeout` on their own. If you don't want to do that, at least use `setTimeout(function() { deferred.resolve(geocode(address)); }, 1000)` to do it correctly – Bergi Feb 05 '16 at 12:45

2 Answers2

2

Your code seems to work fine. The only issue i see with your code is that you are using lat and lng out of scope. But you may have written that correctly and you're just not including the code. I suspect though that you may have been using the two in error. Should those have been geoData.lat and geoData.lng?

var coord = { 'lat': geoData.lat, 'lng': geoData.lng };

Plnkr

EDIT

I think your problem might have to do with your geocodeAll function implementation.

function geocodeAll(addresses)
 {
   for (addr in addresses)
     {
      geocode(addresses[addr]) /* This seems error prone to me!  Try keeping track of all your promises.*/
        .then(
              function(coord)
               {/*You only get here if there was no error returned from the geo request to the api. */}
             )
     }
 }

Keep track using Q.all,

function geocodeAll(addresses) {
  var promises = addresses.map(geocode); 
  for (addr in addresses) {
    promises.push(
      geocode(addresses[addr])
         .catch(console.log.bind(console)) /* handle your error however you see fit*/
      ); 
  }
  return Q.all(promises).then(function(results) {
     var firstCord = results[0];
     var secondCord = results[1];
     //etc...
  });
 }

Or you can additionally handle the success/fail using Q.allSettled

function geocodeAll(addresses) {
      var promises = addresses.map(geocode);
      return Q.allSettled(promises).then(function (results) {
        var success = [], fail = [];
        results.forEach(function (result) {
          if (result.state === "fulfilled") {
             success.push(result.value);
          } else {
            fail.push(result.reason);
          }
        });
        return { coords: success, errors: fail };
      });
     }

   });
bluetoft
  • 5,373
  • 2
  • 23
  • 26
0

Code looks good. Perhaps geocoder.geocode or something else is erring. Try setting:

window.onerror = (err) => console.error(err)

Or:

process.on('uncaughtException', (err) => console.error(err))
Filip Dupanović
  • 32,650
  • 13
  • 84
  • 114