EDITAR:
Esqueci de dizer que essa solução é em js puro, a única coisa que você precisa é de um navegador que suporte promessas https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise
Para aqueles que ainda precisam realizar isso, escrevi minha própria solução que combina promessas com tempos limite.
Código:
/*
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);
}
});
}
};
Observe que é apenas uma parte de uma biblioteca maior que escrevi para lidar com as coisas do Google Maps, portanto, os comentários podem ser confusos.
O uso é bastante simples, a abordagem, no entanto, é um pouco diferente: em vez de fazer um loop e resolver um endereço de cada vez, você precisará passar uma matriz de endereços para a classe e ela cuidará da pesquisa por si mesma, retornando uma promessa que , quando resolvido, retorna uma matriz contendo todos os endereços resolvidos (e não resolvidos).
Exemplo:
var myAmazingGeo = new Geolocalizer();
var locations = ["Italy","California","Dragons are thugs...","China","Georgia"];
myAmazingGeo.Localize(locations).then(function(res){
console.log(res);
});
Saída do console:
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
Objeto devolvido:
Toda a magia acontece aqui:
(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);
Basicamente, ele faz um loop em cada item com um atraso de 750 milissegundos entre cada um deles, portanto, a cada 750 milissegundos, um endereço é controlado.
Fiz mais alguns testes e descobri que mesmo em 700 milissegundos às vezes recebia o erro QUERY_LIMIT, enquanto com 750 não tive nenhum problema.
Em qualquer caso, sinta-se à vontade para editar o 750 acima se achar que está seguro lidando com um atraso menor.
Espero que isso ajude alguém em um futuro próximo;)