title: avoid OVER_QUERY_LIMIT with google maps using setTimeout, unexpected time gaps
body: <p>I'm trying to avoid the dreaded over query limit messages from the google geocode api.</p>
  
  <p>I'm getting my data in batches of 10 from the server. Within one batch the timings are good, but between batches there is a growing delay that I don't understand. I've checked the timing on getting new records but that is subsecond and not the issue.</p>
  
  <p>I'm looking for some guidance on where the gaps are created (and ideally how they can be removed).
  The exact code is below. I basically use a counter that is steady over the different batches, and I use a setTimeout with a timing of <code>(300*counter)</code> to make sure that they don't fire all at the same time. Which again works nicely within a batch, but not over batches.</p>
  
  <p>The timings between the different batches is:</p>
  
  <pre><code>start batch 1 :"2013-03-26 15:40:15.882337"
  stop batch  1 :"2013-03-26 15:40:18.586881"
  start batch 2 :"2013-03-26 15:40:21.688363" (3 seconds between batches)
  stop batch  2 :"2013-03-26 15:40:24.384641"
  start batch 3 :"2013-03-26 15:40:30.449829" (6 seconds between batches)
  stop batch  3 :"2013-03-26 15:40:33.150393"
  start batch 4 :"2013-03-26 15:40:42.216579" (9 seconds between batches)
  stop batch  4 :"2013-03-26 15:40:44.917545"
  start batch 5 :"2013-03-26 15:40:56.991258" (12 seconds between batches)
  stop batch  5 :"2013-03-26 15:40:59.689068"
  start batch 6 :"2013-03-26 15:41:14.742534" (15 seconds between batches)
  stop batch  6 :"2013-03-26 15:41:17.444024"
  start batch 7 :"2013-03-26 15:41:35.500424" (18 seconds between batches)
  </code></pre>
  
  <p>As you can see the gaps between the batches is growing.</p>
  
  <p>The code I use:</p>
  
  <pre><code>  getRecords: function(data, textStatus, xhr) {
  
      var self = this;
      var recordsDone = 0;
  
      if (data) {
        for (var i = 0; i &lt; data.geocode.length; i++) {
  
          // build the address string
          var addressQuery = this.buildAddress(data, i);
  
          setTimeout(function(addr, recId) {
            self.googleGeocoder.geocode({'address': addr}, function(result, status) {
              if (status === google.maps.GeocoderStatus.OK ) {
                $.ajax({
                  url: '/geocode/' + recId + '.json',
                  data: {'status': status, 'lat': result[0].geometry.location.kb, 'long': result[0].geometry.location.lb},
                  type: 'PUT',
                  success: function(data, textStatus, xhr) {
                    var total = parseFloat(data.total);
                    var done = parseFloat(data.done);
                    self.set('voortgang', (done/total)*100);
                  },
                  error: function(xhr, textStatus, errorThrown) {
  
                  }
                });
              } else {
                $.ajax({
                  url: '/geocode/' + recId + '.json',
                  data: {'status': status},
                  type: 'PUT',
                  success: function(datra, textStatus, xhr) {
                    var total = parseFloat(data.total);
                    var done = parseFloat(data.done);
                    self.set('voortgang', (done/total)*100);
                  },
                  error: function(xhr, textStatus, errorThrown) {
  
                  }
                });
              }
  
              recordsDone++;
  
              if (recordsDone === data.geocode.length) {
                console.log('about to get records ' + new Date().toUTCString());
                $.ajax({
                  url: '/geocode.json',
                  data: {data_set_id: self.datasetid},
                  type: 'GET',
                  success: function (data, textStatus, xhr) {
                    console.log('got the records ' + new Date().toUTCString());
                    self.getRecords(data, textStatus, xhr);
                  },
                  error: function(xhr, textStatus, errorThrown) {
                    // set to fully geocoded
                    var found = self.get('content').findProperty('id', self.datasetid);
                    Ember.set(found, 'data_set.fully_geocoded', true);
                    self.set(voortgang, 0);
                  }
                });
              }
            });
          }, (300*this.globalRecordsDone), addressQuery, data.geocode[i].id);
  
          // another record has been handled
          this.globalRecordsDone++;
        }
      }
  
      // get records the first time
      if (this.firstTime === true) {
        $.ajax({
          url: '/geocode.json',
          data: {data_set_id: this.datasetid},
          type: 'GET',
          success: function (data, textStatus, xhr) {
            self.getRecords(data, textStatus, xhr);
          },
          error: function(xhr, textStatus, errorThrown) {
            alert('stop getting records');
          }
        });
  
        this.firstTime = false;
      }
  
    }
  </code></pre>