1

I have the following code to go through an obj:

var data = [];
var obj = {...
};

for (var key in obj) {
  if (!obj[key]["something"]) {
    geocoder.geocode({
      'address': key
    }, function(results, status) {
      if (status === google.maps.GeocoderStatus.OK) {

         data.push({...});

      }
    });

    // if last item
    $.post("...", data, ...);
  }
}

Now I want to post all the data retrieved by running all asynchronous functions called in the loop.

haim770
  • 48,394
  • 7
  • 105
  • 133
sdvnksv
  • 9,350
  • 18
  • 56
  • 108

4 Answers4

3

Since the geocoder.geocode() (that is part of Google Maps API) doesn't return either a Promise or a Deferred, you'll have to encapsulate the request in your own Promise, then use Promise.all():

var promises = [];

for (var key in obj) {
    if (!obj[key]["something"]) {
        promises.push(new Promise(function (resolveWith, rejectWith) {
            geocoder.geocode({
                'address': key
            }, function (results, status) {
                if (status === google.maps.GeocoderStatus.OK) {
                    data.push(...);
                    resolveWith(results);
                } else
                    rejectWith(results);
            });
        }));
    }
}

Promise.all(promises).then(function (resultsArr) {
    // at this point all requests have been fulfilled
    $.post(...);
});

See MDN

haim770
  • 48,394
  • 7
  • 105
  • 133
  • This looks like what I need indeed! Will get back shortly to tell if it's worked. – sdvnksv Oct 09 '16 at 11:08
  • Although getting the following error when the obj has many keys: Uncaught (in promise) null > .. url .. . It works with a single key for some reason. – sdvnksv Oct 09 '16 at 11:28
  • @Deka87, If you're going to iterate on the keys of `obj`, you'll need `for (var key in Object.keys(obj)) { ... }` – haim770 Oct 09 '16 at 11:33
  • Had to move the promises.push() part inside the status === ok block, because otherwise once it had a single reject it didn't post data to the database at all. – sdvnksv Oct 09 '16 at 11:54
0

Try using jQuery.Deferred()

var obj = {...};
var deferred = $.Deferred();
deferred.done(function(){ /*.. asynchronous function here ..*/ });

for (var key in obj) {
  if (!obj[key]["something"]) {
    deferred.resolve();
  }
}
Fourat
  • 2,366
  • 4
  • 38
  • 53
0

You need to know which key is last, but as there are no determinate order to hashed keys in an object it will most likely not turn out the way you want in edge cases.

One way to at least get some kind of last key would be to iterate once before the main loop, like this:

var obj = {...
};

var lastkey;

for (var key in obj) {
  lastkey = key;
}

for (var key in obj) {
  if( key === lastkey) {
    ... do lastkey stuff instead here
  } else {
    if (!obj[key]["something"]) {
      geocoder.geocode({
        'address': key
      }, function(results, status) {
        if (status === google.maps.GeocoderStatus.OK) {
       ...
        }
      });
    }
  }
}

If the 'obj' does not change during or between those 2 loops the last key should turn out the same in both loops.

Karlsson
  • 203
  • 3
  • 13
  • Property order is not guaranteed to be the same between iterations, though in practice it may be. – pinkfloydx33 Oct 09 '16 at 10:55
  • I just thought that getting to the last key of the obj doesn't mean the the last asynchronous function has finished getting the data.. – sdvnksv Oct 09 '16 at 10:56
  • @Deka87 , it will most likely get to the last key of the object long before those asynchronous calls are done. You maybe should ask about how to add a call after all the other calls, and not ask how to get the last key. It will give you better answers. – Karlsson Oct 09 '16 at 11:09
  • @Huggabear, you are right. Updated the question to avoid confusion. – sdvnksv Oct 09 '16 at 11:14
-1
 var data = [];
 var obj = {...
 };

var keys = Object.keys(obj);
 var last = keys[keys.length-1];

for (var key in obj) {
if (!obj[key]["something"]) {
geocoder.geocode({
  'address': key
}, function(results, status) {
  if (status === google.maps.GeocoderStatus.OK) {

     data.push({...});

  }
});

// if last item
if (key == last)
$.post("...", data, ...);
 } 
 }
Umakant Mane
  • 1,001
  • 1
  • 8
  • 9