Google Maps API v3 中的 OVER_QUERY_LIMIT:如何在 Javascript 中暂停/延迟以减慢速度?
Posted
技术标签:
【中文标题】Google Maps API v3 中的 OVER_QUERY_LIMIT:如何在 Javascript 中暂停/延迟以减慢速度?【英文标题】:OVER_QUERY_LIMIT in Google Maps API v3: How do I pause/delay in Javascript to slow it down? 【发布时间】:2012-08-01 08:04:39 【问题描述】:我遇到了一个在这些论坛中讨论得很好的问题,但似乎没有一个建议对我有用,所以我正在寻找一些完整的 javascript,在保存为 html 文件时可以工作。
问题是,当我尝试使用 Javascript 调用的 V3 API 对 Google 地图上的 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);
);
【问题讨论】:
我想如果你提出像 $.getJSON 这样的请求...没有限制 OVER_QUERY_LIMIT while using google maps的可能重复 【参考方案1】:Mike Williams 的教程中没有类似这两行的内容:
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();
);
【讨论】:
也适用于路由,当批处理只是在增加延迟后递归到对 Google 的批处理调用。 这是什么..@Andrew Leach 你能告诉我这些延迟和下一个地址是什么吗..你能解决这个问题吗Fiddledelay
是以毫秒为单位的延迟; nextAddress
是地址计数器:如果地址失败,取消设置增量并增加延迟,以便再次尝试。完整的实现在我的网站上给出的链接:你的小提琴中没有这样的代码。
第一个结果后是否可以设置地图中心?
@PaulLeclerc 我的示例仍然适用于我,尽管地理编码器已更改,因此实际找到的地址更少。如果您使用共享 IP 地址,则查询限制在该 IP 地址上的所有用户之间共享。这意味着移动网络的用户在开始之前可能会违反限制。【参考方案2】:
这个问题的一般答案是:
不要在每次加载页面时对已知位置进行地理编码。对它们进行离线地理编码并使用生成的坐标在您的页面上显示标记。
限制的存在是有原因的。
如果您无法离线对位置进行地理编码,请参阅 Mike Williams 的 v2 教程中的 this page (Part 17 Geocoding multiple addresses),该教程描述了一种方法,将其移植到 v3 API。
【讨论】:
感谢您的回复。我无法对它们进行离线地理编码,但您引用的页面没有提供任何我可以应用的示例。我真正需要的只是一个可以工作的延迟/暂停步骤。 你看到了吗:view-source:econym.org.uk/gmap/example_geomulti.htm,它是为 v2 API 编写的,但这个概念应该适用于 v3 API。 已经尝试过这个概念,但没有成功。它可能在 V2 和 V3 中运行良好,但我无法让它成功应用于上述 Javascript。 您可以发布一个指向您的地图(或 jsfiddle)的链接,您试图让它工作但失败了,也许有人可以看到您哪里出错了。 是的,根据上面的代码,它适用于前 80 次页面浏览量,然后使用免费使用中断。 3300 页面浏览量,如果您付费的话。【参考方案3】:我在这里加载了 2200 个标记。添加 2200 个位置大约需要 1 分钟。 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);
);
【讨论】:
ToS 有一些您应该注意的限制:“不得使用超出交易限制和使用政策。如果您的 Maps API 实施产生大量交易,Google 保留设置交易限制的权利。 Google 还保留不时在文档中设置其他使用政策的权利。如果您想在这些交易限制或使用政策之外进行使用,您可以通过 Maps API 标准定价计划购买更多使用容量,或者您可以请联系 Google 地图销售团队,了解满足您需求的许可选项。” @sachingavas 我收到 name.replace 不是函数错误消息【参考方案4】:使用“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);
【讨论】:
【参考方案5】:这篇文章是不久前发表的,但它提供的答案并没有解决我在迭代中达到请求限制的问题,所以我发布了这篇文章,以帮助其他没有服务的人。
我的环境发生在 Ionic 3 中。
我没有在迭代中“暂停”,而是产生了使用timer
进行迭代的想法,这个计时器具有执行将在迭代中进行的代码的特殊性,但会每隔一段时间运行一次直到达到我们要迭代的“数组”的最大计数。
也就是说,我们会在一定的时间内查询 Google API,使其不超过允许的毫秒数限制。
// Code to start the timer
this.count= 0;
let loading = this.loadingCtrl.create(
content: 'Buscando los mejores servicios...'
);
loading.present();
this.interval = setInterval(() => this.getDistancias(loading), 40);
// Function that runs the timer, that is, query Google API
getDistancias(loading)
if(this.count>= this.datos.length)
clearInterval(this.interval);
else
var sucursal = this.datos[this.count];
this.calcularDistancia(this.posicion, new LatLng(parseFloat(sucursal.position.latitude),parseFloat(sucursal.position.longitude)),sucursal.codigo).then(distancia =>
).catch(error =>
console.log('error');
console.log(error);
);
this.count += 1;
calcularDistancia(miPosicion, markerPosicion, codigo)
return new Promise(async (resolve,reject) =>
var service = new google.maps.DistanceMatrixService;
var distance;
var duration;
service.getDistanceMatrix(
origins: [miPosicion, 'salida'],
destinations: [markerPosicion, 'llegada'],
travelMode: 'DRIVING',
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
, function(response, status)
if (status == 'OK')
var originList = response.originAddresses;
var destinationList = response.destinationAddresses;
try
if(response != null && response != undefined)
distance = response.rows[0].elements[0].distance.value;
duration = response.rows[0].elements[0].duration.text;
resolve(distance);
catch(error)
console.log("ERROR GOOGLE");
console.log(status);
);
);
我希望这会有所帮助!
对不起,我的英语不好,希望不是不便,我不得不使用谷歌翻译。
问候,莱安德罗。
【讨论】:
【参考方案6】:您以错误的方式使用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()
调用都会导致geocoder.geocode()
在上一次调用后100 毫秒后被调用。
我还为标记添加了动画,因此您将获得一个很好的动画效果,标记被添加到一个接一个的地图中。我不确定当前的 google 限制是多少,因此您可能需要增加 delay
变量的值。
此外,如果您每次都对相同的地址进行地理编码,则应将地理编码的结果保存到您的数据库中,下次只需使用它们(这样您将节省一些流量并且您的应用程序会更快一点)
【讨论】:
如何将这段代码实现到我的代码中? jsfiddle.net/395rdhd8我尝试了很多东西,但没有任何运气。STATUS OVER_QUERY_LIMIT
在我的控制台中出现在我的 STATUS.OK
之前。但为什么?谢谢。
你的setTimeout用法不对,setTimeout不是让javascript休眠X秒,它是用来在X秒后运行指定函数
我该如何解决? Javascript 不是我最强的技能。谢谢!
其中一个选项是创建递归函数,如果请求不成功,该函数将调用自身,如下所示:jsfiddle.net/395rdhd8/1以上是关于Google Maps API v3 中的 OVER_QUERY_LIMIT:如何在 Javascript 中暂停/延迟以减慢速度?的主要内容,如果未能解决你的问题,请参考以下文章
可以吗? GMap API V2 中的 clearOverlays() 到 Google Maps API V3?
关闭 Google Maps API v3 中的所有信息窗口
如何更改 Google Maps API V3 中的图标颜色?