3

I was having some problem with Promise in JavaScript. What I am trying to do is I got a list of address, then for each address, I need to call the geocode API to get the lat lng, then I will proceed to plot the markers together with the heatmap. Here is my code:

let promiseKey = Promise.all(
          result.map()
        );

        var addedMarkers = promiseKey.then(
        markers => Promise.all(
          markers.map()
        )
        )
        .then(drawForecastHeatmap);

The part where I call the geocode API:

function getBranchLatLng(address, branchName, total, queKey){
return new Promise(function(resolve){
    var key = jQuery.rand(geoCodKeys);
    var url = 'https://maps.googleapis.com/maps/api/geocode/json?key='+key+'&address='+address+'&sensor=false';

    $.ajaxq (qyName, {
        url: url,
        dataType: 'json'
    }).done(function( data ) {
        var address = getParameterByName('address', this.url);
        var index = errorArray.indexOf(address);
        try{
            var p = data.results[0].geometry.location;
            var latlng = new google.maps.LatLng(p.lat, p.lng);

            var markerItem =
                {
                    'lat': p.lat,
                    'lng': p.lng,
                    'address': address,
                    'branchName': branchName,
                    'total': total,
                };
            console.log(markerItem);
            resolve(markerItem);

            if (index > -1) {
                errorArray.splice(index, 1);
            }
        }catch(e){
            if(data.status = 'ZERO_RESULTS')
                return false;

            //on error call add marker function for same address and keep in Error ajax queue
            getBranchLatLng( address, 'Error' );
            if (index == -1) {
                errorArray.push( address );
            }
        }
    });

    //mentain ajax queue set
    queuCounter++;
    if( queuCounter == setLimit ){
        queuCounter = 0;
    }

});
}

The problem now is, the program just stopped at getBranchLatLng() and never even go into the addForecastMarker() although I managed to print out some lat lng from geocode.

Some of the address returning me:

jquery.min.js:4 GET https://maps.googleapis.com/maps/api/geocode/json?key=&address= 400 ()

Then when I try to extend the link, I am getting this:

error_message: "Invalid request. Missing the 'address', 'bounds', 'components', 'latlng' or 'place_id' parameter."
results :[]
status: "INVALID_REQUEST"

Any ideas on how to resolve those address with 'INVALID_REQUEST' back to the Promise parent?

Thanks!

QWERTY
  • 2,303
  • 9
  • 44
  • 85
  • 3
    you dont use reject in your getBranchLatLng mybe you get an error and that is why the promise stops – Amit Wagner Dec 17 '17 at 08:50
  • @AmitWagner You mean take out the catch() that chunk? – QWERTY Dec 17 '17 at 08:51
  • i mean in your ajax function there is might be some error. try to allways resolve to see if you code continue or use reject and handle the error on the promise chain – Amit Wagner Dec 17 '17 at 08:55
  • https://jsfiddle.net/fLz2h661/ see the code in the catch i add resolve to only for test. you need to to use reject in the catch and handle it – Amit Wagner Dec 17 '17 at 09:00
  • @AmitWagner Is there anyway such that if it is rejected, then I simply skip it instead – QWERTY Dec 17 '17 at 09:04
  • add filter to markers map now the we resolve if error. that sholud skip it https://jsfiddle.net/fLz2h661/2/ – Amit Wagner Dec 17 '17 at 09:12
  • 1
    For starters, you're missing all sorts of error handling. So if any of the promises in any of your `Promise.all()` calls fails, then none of your other code runs. You need error handling everywhere. Might even show you what's going on here. This is a textbook example of bad promise code that ignores errors everywhere. For example, what if your ajax call fails? You do nothing - parent promise isn't rejected or resolved so the `Promise.all()` call will just wait forever. – jfriend00 Dec 17 '17 at 09:58
  • @jfriend00 Any ideas? I am pretty sure the problem is with the getBranchLatLng() because the dummy message I planted at the addForecastMarker() is not printing out – QWERTY Dec 17 '17 at 10:06
  • Yeah, `getBranchLatLng()` isn't checking for errors and isn't making sure that it always resolves or rejects the parent promise, thus sometimes the promise is never resolved or rejected so your logic waits forever. – jfriend00 Dec 17 '17 at 10:26
  • @jfriend00 Any ideas on how to fix this? Or what should I do to trace the error? I tried to change the conditions in catch statement to force everything into resolve but the problem still persist. – QWERTY Dec 17 '17 at 10:57
  • @AmitWagner Hey any ideas on how to skip those with 400() error message? I tried to set an extra if condition to force those with INVALID_REQUEST to resolve back to the promise parent but to no futile. – QWERTY Dec 17 '17 at 11:23
  • What is `$.ajaxq`? Looks like it does return a promise (or jQuery deferred at least) and you should avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Dec 17 '17 at 13:17

1 Answers1

0

It is not possible to generate the working code without having all the test data and undeclared variable that you are using in your code. But overall what I can suggest is that, you must add a catch block to the ajax request, and keep into mind that there must be no workflow in your getBranchLatLng Promise that is not resolving or rejecting the promise.

Assuming that, incase of any error, you still want to resolve your getBranchLatLng, I have updated your code like this, so that there are no workflow in your getBranchLatLng promise that won't resolve or reject

let promiseKey = Promise.all(
          result.map(el=>getBranchLatLng(el.branchAddress, el.branchName, el.amount))
        );

        var addedMarkers = promiseKey.then(
        markers => Promise.all(
          markers.map(marker => addForecastMarker(marker))
        )
        )
        .then(drawForecastHeatmap)
        .catch(functon(e) {
            //Do the error handling here
        });

function getBranchLatLng(address, branchName, total, queKey) {
return new Promise(function(resolve, reject) {
    var key = jQuery.rand(geoCodKeys);
    var url = 'https://maps.googleapis.com/maps/api/geocode/json?key='+key+'&address='+address+'&sensor=false';

    var qyName = '';
    if( queKey ) {
        qyName = queKey;
    } else {
        qyName = 'MyQueue'+queuCounter;
    }

    $.ajaxq (qyName, {
        url: url,
        dataType: 'json'
    }).done(function( data ) {
        var address = getParameterByName('address', this.url);
        var index = errorArray.indexOf(address);
        try{
            var p = data.results[0].geometry.location;
            var latlng = new google.maps.LatLng(p.lat, p.lng);

            var markerItem =
                {
                    'lat': p.lat,
                    'lng': p.lng,
                    'address': address,
                    'branchName': branchName,
                    'total': total,
                };
            console.log(markerItem);
            if (index > -1) {
                errorArray.splice(index, 1);
            }
            resolve(markerItem);

        }catch(e) {
                if (index == -1) {
                errorArray.push( address );
            }
                resolve({type: 'error', status: data.status});

        }
    })
    .catch(function(e) {
        resolve({type: 'error', status: data.status});
      //Instead of resolving with error code you can also reject the promise
      //reject(e);
    });

    //mentain ajax queue set
    queuCounter++;
    if( queuCounter == setLimit ){
        queuCounter = 0;
    }

  }
)};

function addForecastMarker(marker) {
console.log('adddddd markerssssss');
}

But this is not the Boilerplate code that you can use to directly get the final result. You need to add the error handling code when the any of the promise would fail. For your help, I have resolved those promises with type: 'error'. Inside the then block of promiseKey you must read those and do further error handling and remove those from the array before calling addForecastMarker over it.

Hope that it helps.

Sandip Ghosh
  • 719
  • 7
  • 13