Google геокодирует несколько адресов в цикле с javascript, откуда я знаю, когда все будет сделано?
У меня есть форма, которая запрашивает список мест (не много, обычно только 3 или 4, но это число является динамическим). Когда форма отправляется, мне приходится анализировать данные, использовать геокодирование Google для получения местоположений, а затем нарисовать линию, соединяющую точки в порядке. У меня работает синтаксический анализ, но я зациклился на части геокодирования, в основном из-за асинхронного характера. Предположим, что мои адресные строки хранятся в адресах массива, это как далеко я получил:
function someFunction(addresses) {
var coords = [];
for(var i = 0; i < addresses.length; i++) {
currAddress = addresses[i];
var geocoder = new google.maps.Geocoder();
if (geocoder) {
geocoder.geocode({'address':currAddress}, function (results, status)
if (status == google.maps.GeocoderStatus.OK) {
coords.push(results[0].geometry.location);
}
else {
throw('No results found: ' + status);
}
});
}
}
// Initially I tried to work with the data here, but it wasn't all present yet.
}
Рисование линии достаточно просто, я сделал это раньше, когда пользователи предоставили географические координаты lat/lng. Моя проблема в том, что координаты добавляются только в обратном вызове, откуда я знаю, когда это делается? Я не могу просто сбросить это в функцию и включить обратный вызов, потому что мне нужно подождать, пока все координаты не будут обработаны.
Я также читал о ком-то, у кого были проблемы с результатами, которые не вернулись в порядок, но я не понял предоставленного ответа. Если у кого-то есть ответ, который может помочь мне с моей конкретной проблемой и гарантировать, что результаты вернутся в порядок, я бы очень признателен.
NB: Я вручную бомбил этот код, поэтому могут быть опечатки. Мой фактический код до сих пор "работает", я просто не знаю, кто должен перейти от того, что мне нужно делать, когда все адреса обрабатываются. Кроме того, в настоящее время он разрабатывается как внутреннее приложение для тестирования. По завершении тестирования он будет полностью соответствовать Google TOS. Это означает, что у меня нет страницы, на которую я могу ссылаться. Вся заявка также содержит более 2000 строк кода и содержит в свое время некоторую проприетарную информацию о компании, которая в конечном итоге будет постепенно отменена, поэтому вставка всего объекта или отправка его невозможна. Надеюсь, это не представляет слишком большой проблемы.
Ответы
Ответ 1
function someFunction(addresses, callback) {
var coords = [];
for(var i = 0; i < addresses.length; i++) {
currAddress = addresses[i];
var geocoder = new google.maps.Geocoder();
if (geocoder) {
geocoder.geocode({'address':currAddress}, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
coords.push(results[0].geometry.location);
if(coords.length == addresses.length) {
if( typeof callback == 'function' ) {
callback();
}
}
}
else {
throw('No results found: ' + status);
}
});
}
}
}
}
//Usage
someFunction(addresses, function() {
// Do something after getting done with Geocoding of multiple addresses
});
Использование функции обратного вызова удивительно
Ответ 2
Вы можете проверить, завершены ли все вызовы, сравнивая количество результатов с количеством адресов:
function someFunction(addresses) {
var currAddress, coords = [];
for (var i = 0; i < addresses.length; i++) {
currAddress = addresses[i];
var geocoder = new google.maps.Geocoder();
if (geocoder) {
geocoder.geocode({'address':currAddress}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
coords.push(results[0].geometry.location);
// Check if all calls have been processed
if (coords.length == addresses.length) {
someOtherFunction(coords);
}
}
...
});
}
}
}
function someOtherFunction(coords) {
// Geocoding has been done for all addresses
...
}
Ответ 3
Если вы используете такие библиотеки, как jQuery
, вы можете воспользоваться Отложенным объектом для выполнения цепочки запросов через функцию geocoder.geocode
.
Пример
function initMap() {
var geocoder = new google.maps.Geocoder();
var addreses = [
{ "lat": 60.173890, "lng": 24.941025 },
{ "lat": 60.461608, "lng": 22.266598 },
{ "lat": 61.498714, "lng": 23.760940 }
];
var deferreds = getGeocodeAddressDeferred(geocoder,addreses);
$.when.apply($, deferreds).done(function (locations) {
//print results
$.each(arguments, function (i, data) {
$("div#result").append(data + "<br/>");
});
});
}
function getGeocodeAddressDeferred(geocoder, addreses) {
var deferreds = [];
$.each(addreses, function (i,address) {
deferreds.push(geocodeAddress(geocoder, address));
});
return deferreds;
}
function geocodeAddress(geocoder, latLng) {
var deferred = $.Deferred();
geocoder.geocode({ 'location': latLng }, function (results, status) {
if (status === google.maps.GeocoderStatus.OK) {
deferred.resolve(results[0].formatted_address);
}
});
return deferred.promise();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
async defer></script>
<div id="result"/>
Ответ 4
Это довольно старый, но есть проблема закрытия в данных ответах , поэтому конечный результат имеет тот же lat, что и для всех адресов.
Лучше прокручивать все адреса, используя addresses.forEach, чтобы каждый геокодированный адрес содержался, и это должно работать нормально, если целевые браузеры являются современными. В противном случае вам нужно определить внешнюю функцию, чтобы решить проблему javascript позорного цикла. Вот решение forEach для массива адресов:
var getLatLng = function(addresses, callback) {
var coords = [];
addresses.forEach(function(address) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'address': address}, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var lat = results[0].geometry.location.lat();
var lng = results[0].geometry.location.lng();
coords.push([lat, lng]);
// all addresses have been processed
if (coords.length === addresses.length)
callback(coords);
}
});
});
}
getLatLng(allAddresses, function (results) {
console.log("received all addresses:", results);
});