Chris
Chris

Reputation: 33

Add delay between ajax json calls

Sorry in advance if this isn't the proper way to ask this, please let me know how I can improve my questions :)

Essentially I have a json file which I want to pull data from (name, address, etc) in order to use a Google Maps API function to plot them as markers. This is the current ajax function I'm using:

$.ajax({
    url: 'directory.json',
    dataType: 'json',
    type: 'get',
    cache: 'false',
    success: function(data) {
        $(data.group).each(function(index, person) {
        if (typeof person.Address != "undefined") {
            geocodeAddress(geocoder, map, person);
        }
    });
  }
});

However, this is calling the geocodeAddress function for all 800+ of my directory entries all at once, which is far above my Maps API query limit. I'd like to space these out ~100ms apart to prevent this. I tried using setInterval like to accomplish this, but it seems that the geocodeAddress line is run for all entries at once, so this would only delay all of the functions, not the length between each.

Is there another way I could pull this json data instead of using ajax, or just a way to delay each API request individually?

geocodeAddress function for reference (it both geocodes and plots markers)

function geocodeAddress(geocoder, resultsMap, person) {

  //geocoding address
  geocoder.geocode({'address': person.Address[0].text}, function(results, status) {
      if (status === 'OK') {

        //plotting coordinate as marker
        var marker = new google.maps.Marker({
            map: resultsMap,
            position: results[0].geometry.location,
            icon: {
              url: person.Image[0].src,
              size: new google.maps.Size(120, 150),
              scaledSize: new google.maps.Size(30, 38),
              origin: new google.maps.Point(0, 0),
              anchor: new google.maps.Point(15, 19)
            }
        });

      } else {
          console.log("Geocode was not successful for the following reason: " + status);
      }
  });
}

Upvotes: 0

Views: 365

Answers (3)

shakib
shakib

Reputation: 5469

You can loop the geocodeAddress calling with a 100ms spaced out time like below,

$.ajax({
    url: 'directory.json',
    dataType: 'json',
    type: 'get',
    cache: 'false',
    success: function(data) {
        var i = 0;
        var loop = function(){
            if(i < data.group.length){
                if (typeof data.group[i].Address != "undefined")
                   geocodeAddress(geocoder, map, data.group[i]);
                i++; 
                setTimeout(loop, 100);
            }
        }
        loop();
    }
});

hope it helps.

Upvotes: 1

hackerrdave
hackerrdave

Reputation: 6706

You can add delays to your array iteration using setTimeout inside an IIFE:

$.ajax({
  url: 'directory.json',
  dataType: 'json',
  type: 'get',
  cache: 'false',
  success: function(data) {
    //Invoke delayLoop with initial params - i = 0, delay = 100ms
    (delayLoop)(0, data.group, 100, geocodePerson);
  }
});

//Function to perform delayed iteration function on array elements
function delayLoop (i, list, interval, itemFunc) {
  setTimeout(function() {
    itemFunc(list[i]);
    if (++i < list.length) {
      delayLoop(i, list, interval, itemFunc);
    }
  }, interval)
}

//function to perform on array elements
function geocodePerson(person) {
  if (typeof person.Address != "undefined") {
    geocodeAddress(geocoder, map, person);
  }
}

Upvotes: 0

Jaromanda X
Jaromanda X

Reputation: 1

With a little mod to your geocodeAddress function, to add an optional callback

function geocodeAddress(geocoder, resultsMap, person, callback) {
    //geocoding address
    geocoder.geocode({
        'address': person.Address[0].text
    }, function(results, status) {
        if (status === 'OK') {

            //plotting coordinate as marker
            var marker = new google.maps.Marker({
                map: resultsMap,
                position: results[0].geometry.location,
                icon: {
                    url: person.Image[0].src,
                    size: new google.maps.Size(120, 150),
                    scaledSize: new google.maps.Size(30, 38),
                    origin: new google.maps.Point(0, 0),
                    anchor: new google.maps.Point(15, 19)
                }
            });

        } else {
            console.log("Geocode was not successful for the following reason: " + status);
        }
        if (typeof callback == 'function') {
            callback();
        }
    });
}

and, for the sake of minimal changes, adding a wrapper function for geocodeAddress that returns a Promise

function geocodeAddressPromise(geocoder, resultsMap, person) {
    return new Promise(function(resolve) {
        geocodeAddress(geocoder, resultsMap, person, resolve);
    };
}

Your main code can be written as:

$.ajax({
    url: 'directory.json',
    dataType: 'json',
    type: 'get',
    cache: 'false'
}).then(function(data) {
    return data.group.filter(function(person) {
        return typeof person.Address != "undefined";
    }).reduce(function(promise, person) {
        return promise.then(function() {
            return geocodeAddressPromise(geocoder, map, person);
        }).then(function() {
            return new Promise(function(resolve) {
                setTimeout(resolve, 100);
            });
        });
    }, Promise.resolve());
});

it uses .filter to include only persons with an address

and a fairly common .reduce pattern to chain Promises in sequence, with the addition of the 100ms timeout between resolution of one address to the start of the next geocode call

Upvotes: 0

Related Questions