A more graceful way to throttle jQuery's $ ().

I'm trying to use jQuery to $().each

through inputs, make an AJAX call based on two inputs, and update the third input. However, the AJAX call (reverse geocoding Google Maps) has a call limit, that is, I have to limit the number of requests I make per second.

I'm trying to disable each

by calling setTimeout with a timeout that increases by 2 seconds for each iteration, but it just calls them right away. Any ideas on what I am doing wrong? I'm basing my approach on this question , but a few things - especially the fact that the affected elements change with each iteration - make it a little trickier.

<button class="identify-locations">Identify locations</button>

<div class="row">
    <input class="address"></input>
    <input class="lat"></input>
    <input class="lng"></input>
</div>
<!-- the same thing over again 30 times -->

<script>
    $(".identify-locations").click(function(event){
        var time = 2000;
        $(".row").each(function(){
            if($(this).find(".lat").val() == '' && $(this).find(".lng").val() == ''){
                setTimeout( geocodeLocation($(this)), time);
                time += 2000;
            }
        });
    });

    function geocodeLocation(object, time){
        address = object.find(".address").val();
        var geocoder = new google.maps.Geocoder();
        geocoder.geocode({address: address},
            function(results_array, status) {
                if(status == 'OK'){
                    object.find(".lat").val( parseFloat(results_array[0].geometry.location.lat()) ); 
                    object.find(".lng").val( parseFloat(results_array[0].geometry.location.lng()) );
                    updateCount();
                }
        });
    }

</script>

      

+3


source to share


3 answers


You call setTimeout with a function that returns the result immediately.

Instead of this

if($(this).find(".lat").val() == '' && $(this).find(".lng").val() == ''){
 var $current = $(this);
 setTimeout(function() { geocodeLocation($current)}, time);
 time += 2000;
}

      



Also check Passing Parameters to Closure for setTimeout

Please note that useful .bind is not available in IE8 / Safari5

+1


source


the problem is that you are calling the geocodeLocation function at:

setTimeout( geocodeLocation($(this)), time);

      



instead, you should only point to your label. Therefore, it should be:

setTimeout( geocodeLocation.bind(null, $(this)), time);

      

+1


source


Try to use index

.each()

 var time = 2000;
 $(".row").each(function(index){
   if($(this).find(".lat").val() == '' 
      && $(this).find(".lng").val() == '') {
        setTimeout(function() { 
          geocodeLocation($(this))
        }.bind(this), index * time);                    
   }
 });

      

+1


source







All Articles