Maxim Shoustin Maxim Shoustin - 1 month ago 19
Ajax Question

How to run angularjs ajax request in loop but with delay?

I need to run 20-200 ajax requests in loop but to do not hurt

google.maps.Geocoder
I want to set delay 10 sec between each call. However
ajax
request is asynchronous therefore I call next
ajax
request on response succeeded of previous one. If I get response too quick, the delay should take place.

Here is a code I wrote so far:

...
$scope.addressList = ....;
$scope.taskCount = $scope.addressList.length;

geoTaskLoopAsync();

function geoTaskLoopAsync(){

// on success douncount taskCount
var geo = new google.maps.Geocoder();
geocoder.geocode( {
'address': address
}, function(results, status) {
$scope.$apply( function () {
// do something with response

if($scope.taskCurr <= $scope.taskCount){
$scope.taskCurr++;
return geoTaskLoopAsync();
}

return;
});
});


So what next?

can I add something like:

stop = $timeout(function() {
if($scope.taskCurr <= $scope.taskCount){
geoTaskLoopAsync();
} else {
$timeout.cancel(stop);
}
}, 10000);


or have I other way?

Thank you,

Answer

This seems like a great use case for promises and the $q service.

Here's a rough sketch of what using promises might look like. I declare a delay service to handle the 10 second delay and a maps service to handle the geocoding. Both services return promises, and the controller can combine the promises using $q.all() to ensure that there is at least a 10 second delay between Google API calls.

angular.module( /* load your module */ ).service('delay', ['$q', '$timeout', function ($q, $timeout) {
    return {
        start: function () {
            var deferred = $q.defer();
            $timeout(deferred.resolve, 10000);
            return deferred.promise;
        }
    };
}]);

angular.module( /* load your module */ ).service('maps', ['$q', function ($q) {
    var geocoder = new google.maps.Geocoder();
    return {
        geocode: function (address) {
            var deferred = $q.defer();

            geocoder.geocode({
                'address': address
            }, function (results, status) {
                deferred.resolve(results);
                // Should also reject if AJAX errors.
            });

            return deferred.promise;
        }
    };
}]);


angular.module( /* load your module */ ).controller('geocodingController', ['delay', 'maps', '$q', function (delay, maps, $q) {
    var addresses = [/* An array of addresses to geocode */],
        addressIndex = 0,
        geocodeAddresses = function geocodeAddresses() {
            // Use $q.all so that the callback will execute when the geocoding is done AND 10 seconds have passed.
            $q.all([delay.start(), maps.geocode(addresses[addressIndex])]).then(function (results) {
                addressIndex += 1;
                var geocodedData = results[1]; // The geocode result is in the second index.

                // Do something with the results.

                if (addressIndex < addresses.length) {
                    geocodeAddresses();
                }
            });
        };

    // Kick off the AJAX requests.
    geocodeAddresses();
}]);