OVER_QUERY_LIMIT na API do Google Maps v3: Como faço para pausar / atrasar o Javascript para desacelerá-lo?

Eu estou acertando um problema que é bem discutido nestes fóruns, mas nenhuma das recomendações parecem estar funcionando para mim, então eu estou procurando algum javascript completo que funciona quando salvo como um arquivo html.

O problema é que estou sempre com o erro OVER_QUERY_LIMIT ao tentar geocodificar> 11 locais em um mapa do Google usando as APIs da V3 chamadas por Javascript. Eu entendo que há um limite para a taxa na qual você pode chamar o geocoder (assim como o limite diário no volume total), então eu preciso introduzir uma pausa entre cada resultado na matriz.

Qualquer ajuda muito apreciada.

Aqui está o meu código:

  var geocoder; var map; var wait = false; function initialize() { geocoder = new google.maps.Geocoder(); var latlng = new google.maps.LatLng(51.32, 0.5); var myOptions = { zoom: 8, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP } map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); codeAddress('KT16 8LA' + ', UK'); codeAddress('LS8 2LQ' + ', UK'); codeAddress('NE13 8AF' + ', UK'); codeAddress('KT12 2BE' + ', UK'); codeAddress('W1W 8AN' + ', UK'); codeAddress('EC3N 2LS' + ', UK'); codeAddress('BS9 3BH' + ', UK'); codeAddress('KA10 6LZ' + ', UK'); codeAddress('EC1V 9BW' + ', UK'); codeAddress('WD18 8YN' + ', UK'); codeAddress('HA3 6DQ' + ', UK'); codeAddress('W1U 3PL' + ', UK'); codeAddress('W1T 7QL' + ', UK'); codeAddress('W1S 1TD' + ', UK'); codeAddress('SW1X 8NX' + ', UK'); codeAddress('LE2 8ET' + ', UK'); codeAddress('BA3 4BH' + ', UK'); codeAddress('AL3 8JP' + ', UK'); codeAddress('DE55 4QJ' + ', UK'); codeAddress('W6 0QT' + ', UK'); codeAddress('LA1 1PP' + ', UK'); codeAddress('SW16 4DH' + ', UK'); codeAddress('WC2N 6DF' + ', UK'); codeAddress('RM6 6LS' + ', UK'); codeAddress('S25 3QZ' + ', UK'); codeAddress('WC2H 7LR' + ', UK'); codeAddress('BH24 1DW' + ', UK'); codeAddress('EC2N 6AR' + ', UK'); codeAddress('W1U 2FA' + ', UK'); codeAddress('B60 3DX' + ', UK'); } function codeAddress(vPostCode) { if (geocoder) { geocoder.geocode( { 'address': "'" + vPostCode + "'"}, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { map.setCenter(results[0].geometry.location); var marker = new google.maps.Marker({ map: map, position: results[0].geometry.location }); } else { alert("Geocode was not successful for the following reason: " + status); } }); } }   

EDIT: Isso é o que eu tentei fazer para fazer uma pausa / esperar na seção relevante, mas não faz nada:

 function codeAddress(vPostCode) { if (geocoder) { while (wait) { /* Just wait. */ }; geocoder.geocode( { 'address': "'" + vPostCode + "'"}, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { map.setCenter(results[0].geometry.location); var marker = new google.maps.Marker({ map: map, position: results[0].geometry.location }); /* When geocoding "fails", see if it was because of over quota error: */ } else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) { wait = true; setTimeout("wait = true", 2000); //alert("OQL: " + status); } else { alert("Geocode was not successful for the following reason: " + status); } }); } } 

Nada como estas duas linhas aparece no tutorial de Mike Williams:

  wait = true; setTimeout("wait = true", 2000); 

Aqui está uma porta da versão 3:

http://acleach.me.uk/gmaps/v3/plotaddresses.htm

O bit de código relevante é

  // ====== Geocoding ====== function getAddress(search, next) { geo.geocode({address:search}, function (results,status) { // If that was successful if (status == google.maps.GeocoderStatus.OK) { // Lets assume that the first marker is the one we want var p = results[0].geometry.location; var lat=p.lat(); var lng=p.lng(); // Output the data var msg = 'address="' + search + '" lat=' +lat+ ' lng=' +lng+ '(delay='+delay+'ms)
'; document.getElementById("messages").innerHTML += msg; // Create a marker createMarker(search,lat,lng); } // ====== Decode the error status ====== else { // === if we were sending the requests to fast, try this one again and increase the delay if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) { nextAddress--; delay++; } else { var reason="Code "+status; var msg = 'address="' + search + '" error=' +reason+ '(delay='+delay+'ms)
'; document.getElementById("messages").innerHTML += msg; } } next(); } ); }

A resposta geral para esta pergunta é:

Não geocodifique locais conhecidos toda vez que você carregar sua página. Geocodifique-os off-line e use as coordenadas resultantes para exibir os marcadores em sua página.

Os limites existem por um motivo.

Se você não puder geocodificar os locais off-line, consulte esta página (Parte 17 Geocodificando Vários Endereços) no tutorial v2 de Mike Williams, que descreve uma abordagem, porta para a API v3.

Aqui eu tenho carregado 2200 marcadores. Demora cerca de 1 min para adicionar 2200 locais. https://jsfiddle.net/suchg/qm1pqunz/11/

 //function to get random element from an array (function($) { $.rand = function(arg) { if ($.isArray(arg)) { return arg[$.rand(arg.length)]; } else if (typeof arg === "number") { return Math.floor(Math.random() * arg); } else { return 4; // chosen by fair dice roll } }; })(jQuery); //start code on document ready $(document).ready(function () { var map; var elevator; var myOptions = { zoom: 0, center: new google.maps.LatLng(35.392738, -100.019531), mapTypeId: google.maps.MapTypeId.ROADMAP }; map = new google.maps.Map($('#map_canvas')[0], myOptions); //get place from inputfile.js var placesObject = place; errorArray = []; //will fire 20 ajax request at a time and other will keep in queue var queuCounter = 0, setLimit = 20; //keep count of added markers and update at top totalAddedMarkers = 0; //make an array of geocode keys to avoid the overlimit error var geoCodKeys = [ 'AIzaSyCF82XXUtT0vzMTcEPpTXvKQPr1keMNr_4', 'AIzaSyAYPw6oFHktAMhQqp34PptnkDEdmXwC3s0', 'AIzaSyAwd0OLvubYtKkEWwMe4Fe0DQpauX0pzlk', 'AIzaSyDF3F09RkYcibDuTFaINrWFBOG7ilCsVL0', 'AIzaSyC1dyD2kzPmZPmM4-oGYnIH_0x--0hVSY8' ]; //funciton to add marker var addMarkers = function(address, queKey){ var key = jQuery.rand(geoCodKeys); var url = 'https://maps.googleapis.com/maps/api/geocode/json?key='+key+'&address='+address+'&sensor=false'; var qyName = ''; if( queKey ) { qyName = queKey; } else { qyName = 'MyQueue'+queuCounter; } $.ajaxq (qyName, { url: url, dataType: 'json' }).done(function( data ) { var address = getParameterByName('address', this.url); var index = errorArray.indexOf(address); try{ var p = data.results[0].geometry.location; var latlng = new google.maps.LatLng(p.lat, p.lng); new google.maps.Marker({ position: latlng, map: map }); totalAddedMarkers ++; //update adde marker count $("#totalAddedMarker").text(totalAddedMarkers); if (index > -1) { errorArray.splice(index, 1); } }catch(e){ if(data.status = 'ZERO_RESULTS') return false; //on error call add marker function for same address //and keep in Error ajax queue addMarkers( address, 'Errror' ); if (index == -1) { errorArray.push( address ); } } }); //mentain ajax queue set queuCounter++; if( queuCounter == setLimit ){ queuCounter = 0; } } //function get url parameter from url string getParameterByName = function ( name,href ) { name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]"); var regexS = "[\\?&]"+name+"=([^&#]*)"; var regex = new RegExp( regexS ); var results = regex.exec( href ); if( results == null ) return ""; else return decodeURIComponent(results[1].replace(/\+/g, " ")); } //call add marker function for each address mention in inputfile.js for (var x = 0; x < placesObject.length; x++) { var address = placesObject[x]['City'] + ', ' + placesObject[x]['State']; addMarkers(address); } }); 

Usando “setInterval” e “clearInterval” corrige o problema:

 function drawMarkers(map, markers) { var _this = this, geocoder = new google.maps.Geocoder(), geocode_filetrs; _this.key = 0; _this.interval = setInterval(function() { _this.markerData = markers[_this.key]; geocoder.geocode({ address: _this.markerData.address }, yourCallback(_this.markerData)); _this.key++; if ( ! markers[_this.key]) { clearInterval(_this.interval); } }, 300); } 

Você está usando setTimeout errado. A assinatura de function (uma das) é setTimeout(callback, delay) . Assim, você pode especificar facilmente qual código deve ser executado após o atraso.

 var codeAddress = (function() { var index = 0; var delay = 100; function GeocodeCallback(results, status) { if (status == google.maps.GeocoderStatus.OK) { map.setCenter(results[0].geometry.location); new google.maps.Marker({ map: map, position: results[0].geometry.location, animation: google.maps.Animation.DROP }); console.log(results); } else alert("Geocode was not successful for the following reason: " + status); }; return function(vPostCode) { if (geocoder) setTimeout(geocoder.geocode.bind(geocoder, { 'address': "'" + vPostCode + "'"}, GeocodeCallback), index*delay); index++; }; })(); 

Dessa forma, cada chamada codeAddress() resultará em geocoder.geocode() sendo chamado 100ms depois da chamada anterior.

Também adicionei animação ao marcador para que você tenha um belo efeito de animação com marcadores sendo adicionados para mapear um após o outro. Não tenho certeza qual é o limite atual do Google, portanto, talvez seja necessário aumentar o valor da variável de delay .

Além disso, se você estiver geocodificando os mesmos endereços toda vez, deverá salvar os resultados do geocódigo no seu database e, da próxima vez, usá-los (para economizar tráfego e seu aplicativo será um pouco mais rápido)