Подтвердить что ты не робот

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 строк кода и содержит в свое время некоторую проприетарную информацию о компании, которая в конечном итоге будет постепенно отменена, поэтому вставка всего объекта или отправка его невозможна. Надеюсь, это не представляет слишком большой проблемы.

4b9b3361

Ответ 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);
        });