Google Maps API v3中的OVER_QUERY_LIMIT:如何暂停/延迟Javascript以减慢速度?
我遇到了一个在这些论坛讨论的问题,但没有一个build议似乎为我工作,所以我正在寻找一些完整的JavaScript工作时,保存为一个HTML文件。
问题是当我尝试使用JavaScript调用的V3 API在Google Map上对地理位置进行地理编码> 11个位置时,我总是碰到OVER_QUERY_LIMIT错误。 我知道,您可以调用地理编码器的速率(以及总量的每日限制)有一个限制,所以我需要在数组中的每个结果之间引入一个暂停。
任何帮助非常感谢。
这是我的代码:
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <script type="text/javascript"> 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); } }); } } </script> <body style="margin:0px; padding:0px;" onload="initialize()"> <div id="map_canvas" style="width:100%; height:90%"></div> </body>
编辑:这是我试图让它暂停/等待在相关的部分,但它没有做任何事情:
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); } }); } }
迈克·威廉斯的教程中没有像这两行出现:
wait = true; setTimeout("wait = true", 2000);
这是一个版本3端口:
http://acleach.me.uk/gmaps/v3/plotaddresses.htm
相关位的代码是
// ====== 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)<br>'; 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)<br>'; document.getElementById("messages").innerHTML += msg; } } next(); } ); }
这个问题的一般答案是:
每次加载页面时都不要对已知地点进行地理编码。 对它们进行离线地理编码,并使用得到的坐标在页面上显示标记。
这个限制是有原因的。
如果您无法对脱机地点进行地理编码,请参阅Mike Williams的v2教程(参见第17部分地址parsing多个地址) ,该教程描述了一种方法,将其移植到v3 API。
这里我已经加载了2200个标记。 需要大约1分钟,增加2200个地点。 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); } });
使用“setInterval”&“clearInterval”修复问题:
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); }
你正在使用setTimeout
错误的方式。 (其中之一)函数签名是setTimeout(callback, delay)
。 所以你可以很容易地指定在什么延迟之后应该运行什么代码。
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++; }; })();
这样,每次codeAddress()
调用都会导致codeAddress()
在上次调用后的100ms之后被调用。
我还将animation添加到标记中,这样您就可以获得很好的animation效果,标记被添加到一个接一个地图中。 我不确定目前的谷歌限制是什么,所以你可能需要增加delay
variables的值。
另外,如果您每次对相同的地址进行地理编码,则应该将地理编码的结果保存到您的数据库中,下次只使用这些地址(这样您将节省一些stream量,并且您的应用程序会更快一些)