MODIFICARE:
Ho dimenticato di dire che questa soluzione è in puro js, l'unica cosa di cui hai bisogno è un browser che supporti le promesse https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise
Per coloro che hanno ancora bisogno di farlo, ho scritto la mia soluzione che combina le promesse con i timeout.
Codice:
var Geolocalizer = function () {
this.queue = [];
this.resolved = [];
this.geolocalizer = new google.maps.Geocoder();
};
Geolocalizer.prototype = {
Localize: function ( needles ) {
var that = this;
for ( var i = 0; i < needles.length; i++ ) {
this.queue.push(needles[i]);
}
return new Promise (
function (resolve, reject) {
that.resolveQueueElements().then(function(resolved){
resolve(resolved);
that.queue = [];
that.resolved = [];
});
}
);
},
resolveQueueElements: function (callback) {
var that = this;
return new Promise(
function(resolve, reject) {
(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);
var it = setInterval(function(){
if (that.queue.length == that.resolved.length) {
resolve(that.resolved);
clearInterval(it);
}
}, 1000);
}
);
},
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);
}
});
}
};
Tieni presente che è solo una parte di una libreria più grande che ho scritto per gestire le cose di Google Maps, quindi i commenti potrebbero creare confusione.
L'utilizzo è abbastanza semplice, l'approccio, tuttavia, è leggermente diverso: invece di ripetere in loop e risolvere un indirizzo alla volta, dovrai passare un array di indirizzi alla classe che gestirà la ricerca da sola, restituendo una promessa che , una volta risolto, restituisce un array contenente tutti gli indirizzi risolti (e irrisolti).
Esempio:
var myAmazingGeo = new Geolocalizer();
var locations = ["Italy","California","Dragons are thugs...","China","Georgia"];
myAmazingGeo.Localize(locations).then(function(res){
console.log(res);
});
Uscita 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
Oggetto restituito:
L'intera magia avviene qui:
(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);
Fondamentalmente, esegue il loop di ogni elemento con un ritardo di 750 millisecondi tra ciascuno di essi, quindi ogni 750 millisecondi viene controllato un indirizzo.
Ho fatto ulteriori test e ho scoperto che anche a 700 millisecondi a volte ricevevo l'errore QUERY_LIMIT, mentre con 750 non ho avuto alcun problema.
In ogni caso, sentiti libero di modificare il 750 sopra se ritieni di essere al sicuro gestendo un ritardo inferiore.
Spero che questo aiuti qualcuno nel prossimo futuro;)