0

I am writing an app that uses the google javascript api; Everything is working splendidly, until I want to add the reverse geo-coding.

The problem that I have is as follows: I am making a call to this method below, geocodeLatLng, per record, for a minimum of one record.

I have put traces in, and the it will print out as follows:

coordinates: -33.88091325759888, 18.635687828063965

coordinates: -33.874990940093994, 18.639239072799683

coordinates: -33.90454888343811, 18.627684116363525

coordinates: -33.849005699157715, 18.63781213760376

coordinates: -33.85634422302246, 18.639850616455078

then after this, it prints out:

returned status is: OK (x5)

I would really want each call to the geocodeLatLng method to be completed in its entirety, before the next one attempts to start processing. How do I accomplish this?

function geocodeLatLng(callID, lat, lng) {
    var returnString = "";
    var latlng = {lat,lng};
    console.log("coordinates: " + lat + ", " + lng);
    var geocoder = new google.maps.Geocoder;

    geocoder.geocode({'location': latlng}, function(results, status) {
        console.log("returned status is: " + status);
        if (status === 'OK') {
            if (results[0]) {
                var marker = new google.maps.Marker({position: latlng,});
                returnString =  results[0].formatted_address;
                id_address_map.set(callID, returnString);

            } else {
                returnString = 'Address unknown';
                id_address_map.set(callID, returnString);
            }
        } else {
            returnString = 'Geocoder failed due to: ' + status;
            id_address_map.set(callID, returnString);
        }   
    }); 
}

Proposed solution:

function asyncGeoCode(callID, lat, lng) {
    var returnString = "";
    var latlng = {lat,lng};
    console.log("coordinates: " + lat + ", " + lng);
    var geocoder = new google.maps.Geocoder;

      return new Promise((resolve, reject) => {


        geocoder.geocode({'location': latlng}, function(results, status) {
            if (status === "OK") { resolve(results);}
            else {reject("some error msg")}
        });
    });
}

}

and when it is called:

for(var i = 0; i< markers.length; i++) {
    asyncGeoCode(markers[i].CallID, markers[i].Latitude, markers[i].Longitude)
        .then(
            function() {
                console.log("the address is known");
            },

            function(err) {
                console.log("unknown address");
            }
        );
}
Harriet
  • 1,633
  • 5
  • 22
  • 36
  • do you run it in a node environment or on the browser? and do you use any transpilers e.g. Babel? – mbehzad Sep 11 '17 at 10:08

1 Answers1

1

you could wrap it as a promise. something like:

function asyncGeoCode(callID, lat, lng) {
  // ...
  return new Promise((resolve, reject)) => {
    geocoder.geocode({'location': latlng}, function(results, status) {
      if (status === "OK") { resolve(results);}
      else {reject("some error msg")}
    }
  })

}

and use it like

asyncGeoCode("foo", 1, 2)
  .then(resultsFormFirsCall => asyncGeoCode("bar", 123, 321))
  ...
  .then(() => console.log("all calls done one after the other"))

and if you can use es7 async/await:

// in some async function or an async IIFE 
await asyncGeoCode("foo", 1, 2);
await asyncGeoCode("bar", 123, 321);

in case you are stuck with es5 and can not use async/await or generator functions. then you could do something like:

function asyncRecursiveGeoCall(index) {
  return asyncGeoCode(/*info from markers[index]*/)
    .then(function() {
      if (index < markers.length - 1) {return asyncRecursiveGeoCall(index + 1)}
      else {return Promise.resolve()}
    })
}
asyncRecursiveGeoCall(0).then(() => console.log("all done"))
mbehzad
  • 3,758
  • 3
  • 22
  • 29
  • Hi @user2520818. I have used your advice along with MDN to setup a proposed solution. I am having trouble calling the method the way you propose though. Any change you may be able to take a look again? tx H – Harriet Sep 11 '17 at 10:03
  • May be it's better to use Promises.All instead of then . then . then ? – Vyacheslav Sep 11 '17 at 10:05
  • the promlem with Promise.all is that they are run in parallel. i think th op wanted them to be one after the other – mbehzad Sep 11 '17 at 10:06
  • I run it in the browser; I do not have any transpiler – Harriet Sep 11 '17 at 10:13
  • is it important to know the moment when all calls are done? – mbehzad Sep 11 '17 at 10:19
  • i wouldn't say so - just that it executes asynchronously – Harriet Sep 11 '17 at 12:19
  • OK, so I am reading up on Promises - in the mean time, how exactly do I access the returned promise object? in my example I can get access to err.message in the error case, but how do I access my results[] object? – Harriet Sep 11 '17 at 13:13
  • for a single return value it is simple: `function someFuncReturningPromis() {return Promise.resolve(23);} someFuncReturningPromis().then(function(returnedValue) {returnedValue === 23})`. but if you need to chain them, then you have to pass an array in your function, push your value to that array, and return than in your promise – mbehzad Sep 11 '17 at 13:54
  • i am going through what you are saying right now. The solution can be both ways for me actually. Atm I am trying single value, and in the receiving function I push a string holding address value in an array. The alternative will also solve my problem. Will let you know whether it worked for me... – Harriet Sep 11 '17 at 14:04