使用谷歌地理编码器 v3,如果我尝试对 20 个地址进行地理编码,我会得到一个 OVER_QUERY_LIMIT,除非我将它们间隔约 1 秒,但在我的标记全部放置之前需要 20 秒。
除了预先存储坐标之外,还有其他方法可以做到吗?
使用谷歌地理编码器 v3,如果我尝试对 20 个地址进行地理编码,我会得到一个 OVER_QUERY_LIMIT,除非我将它们间隔约 1 秒,但在我的标记全部放置之前需要 20 秒。
除了预先存储坐标之外,还有其他方法可以做到吗?
不,真的没有任何其他方式:如果您有很多位置并想在地图上显示它们,最好的解决方案是:
当然,这是考虑到您对位置的创建/修改比对位置进行咨询要少得多。
是的,这意味着您在保存位置时需要做更多的工作——但这也意味着:
您实际上不必为每个请求等待一整秒。我发现如果我在每个请求之间等待 200 毫秒,我就可以避免 OVER_QUERY_LIMIT 响应并且用户体验还可以。使用此解决方案,您可以在 4 秒内加载 20 个项目。
$(items).each(function(i, item){
setTimeout(function(){
geoLocate("my address", function(myLatlng){
...
});
}, 200 * i);
}
不幸的是,这是谷歌地图服务的限制。
我目前正在使用地理编码功能开发一个应用程序,并且我正在为每个用户保存每个唯一的地址。我根据谷歌地图返回的信息生成地址信息(城市、街道、州等),然后将纬度/经度信息也保存在数据库中。这可以防止您重新编码,并为您提供格式良好的地址。
您想要这样做的另一个原因是,可以从特定 IP 地址进行地理编码的地址数量存在每日限制。你不希望你的申请因为这个原因而失败。
我在尝试对 140 个地址进行地理编码时遇到了同样的问题。
我的解决方法是为下一个地理编码请求的每个循环添加usleep(100000)。如果请求的状态为OVER_QUERY_LIMIT,则usleep 增加50000 并重复请求,以此类推。
由于所有接收到的数据(纬度/经度)都存储在 XML 文件中,因此不会在每次加载页面时都运行请求。
编辑:
忘了说这个方案是纯js的,你唯一需要的是一个支持promise 的浏览器https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise
对于那些仍然需要完成此类任务的人,我编写了自己的解决方案,将 promise 与超时相结合。
代码:
/*
class: Geolocalizer
- Handles location triangulation and calculations.
-- Returns various prototypes to fetch position from strings or coords or dragons or whatever.
*/
var Geolocalizer = function () {
this.queue = []; // queue handler..
this.resolved = [];
this.geolocalizer = new google.maps.Geocoder();
};
Geolocalizer.prototype = {
/*
@fn: Localize
@scope: resolve single or multiple queued requests.
@params: <array> needles
@returns: <deferred> object
*/
Localize: function ( needles ) {
var that = this;
// Enqueue the needles.
for ( var i = 0; i < needles.length; i++ ) {
this.queue.push(needles[i]);
}
// return a promise and resolve it after every element have been fetched (either with success or failure), then reset the queue.
return new Promise (
function (resolve, reject) {
that.resolveQueueElements().then(function(resolved){
resolve(resolved);
that.queue = [];
that.resolved = [];
});
}
);
},
/*
@fn: resolveQueueElements
@scope: resolve queue elements.
@returns: <deferred> object (promise)
*/
resolveQueueElements: function (callback) {
var that = this;
return new Promise(
function(resolve, reject) {
// Loop the queue and resolve each element.
// Prevent QUERY_LIMIT by delaying actions by one second.
(function loopWithDelay(such, queue, i){
console.log("Attempting the resolution of " +queue[i-1]);
setTimeout(function(){
such.find(queue[i-1], function(res){
such.resolved.push(res);
});
if (--i) {
loopWithDelay(such,queue,i);
}
}, 1000);
})(that, that.queue, that.queue.length);
// Check every second if the queue has been cleared.
var it = setInterval(function(){
if (that.queue.length == that.resolved.length) {
resolve(that.resolved);
clearInterval(it);
}
}, 1000);
}
);
},
/*
@fn: find
@scope: resolve an address from string
@params: <string> s, <fn> Callback
*/
find: function (s, callback) {
this.geolocalizer.geocode({
"address": s
}, function(res, status){
if (status == google.maps.GeocoderStatus.OK) {
var r = {
originalString: s,
lat: res[0].geometry.location.lat(),
lng: res[0].geometry.location.lng()
};
callback(r);
}
else {
callback(undefined);
console.log(status);
console.log("could not locate " + s);
}
});
}
};
请注意,它只是我为处理谷歌地图而编写的更大库的一部分,因此评论可能会令人困惑。
用法很简单,但是方法略有不同:不是一次循环和解析一个地址,您需要将地址数组传递给类,它会自行处理搜索,返回一个Promise, 解析后,返回一个包含所有已解析(和未解析)地址的数组。
例子:
var myAmazingGeo = new Geolocalizer();
var locations = ["Italy","California","Dragons are thugs...","China","Georgia"];
myAmazingGeo.Localize(locations).then(function(res){
console.log(res);
});
控制台输出:
Attempting the resolution of Georgia
Attempting the resolution of China
Attempting the resolution of Dragons are thugs...
Attempting the resolution of California
ZERO_RESULTS
could not locate Dragons are thugs...
Attempting the resolution of Italy
返回的对象:
整个魔术发生在这里:
(function loopWithDelay(such, queue, i){
console.log("Attempting the resolution of " +queue[i-1]);
setTimeout(function(){
such.find(queue[i-1], function(res){
such.resolved.push(res);
});
if (--i) {
loopWithDelay(such,queue,i);
}
}, 750);
})(that, that.queue, that.queue.length);
基本上,它在每个项目之间以 750 毫秒的延迟循环每个项目,因此每 750 毫秒控制一个地址。
我做了一些进一步的测试,我发现即使在 700 毫秒时我有时也会收到 QUERY_LIMIT 错误,而使用 750 时我根本没有任何问题。
在任何情况下,如果您觉得通过处理较低的延迟是安全的,请随意编辑上面的 750。
希望这能在不久的将来对某人有所帮助;)