javascript - google geocode - проблема с замыканием / зацикливанием

Я постоянно вызываю функцию API Google в цикле. Каждый раз я хочу удалить один элемент массива адресов.

for(var i = 0; i < AddressObject.addressToArray.length; i++ ){              
  srPerformGeocode(AddressObject);    
  console.log(AddressObject.addressToArray);
  AddressObject.addressToArray.splice(0, 1);                
}
    // --------------------------------------------------------------
    //  Perform geocoding 
    // --------------------------------------------------------------
    function srPerformGeocode(AddressObject)
    {       
        address = AddressObject.addressToArray.join(",");   
        console.log(AddressObject.addressToArray);      
        if (geocoder){                      
            geocoder.geocode({'address': address.trim() }, function (results, status) 
            {                                           
                if (status == google.maps.GeocoderStatus.OK){                   
                    console.log("geocoded " + AddressObject.addressToArray);
                                        // Do something 
                }
                else{                   
                    alert("FAIL");
                }
            }); 
        }
    }

Кажется, что происходит то, что цикл выполняется i раз, а функция srPerformGeocode выполняется i раз каждый раз, используя последнее значение цикла i.

['field1' ,'field2' ,'field3' ,'field4' ]
['field1' ,'field2' ,'field3' ]
['field1' ,'field2'  ]
['field1'  ]
geocoded field1
geocoded field1
geocoded field1
geocoded field1

person Mustapha George    schedule 30.01.2012    source источник
comment
возможный дубликат закрытия Javascript внутри циклов - простой практический пример   -  person rds    schedule 17.01.2013


Ответы (2)


Это не проблема закрытия, потому что вы никогда не закрываете какие-либо переменные (кроме address в srPerformGeocode, но это несущественно для вашей проблемы). Подробнее о закрытии читайте здесь.

JavaScript передает объекты по ссылке 1, поэтому вы передаете один и тот же массив на каждой итерации. цикла (и, следовательно, каждый вызов srPerformGeocode).

На самом деле это нормально до тех пор, пока не будет выполнен асинхронный обратный вызов, служба геокодирования вызывается с параметрами, которые вы видите в первом наборе выходных данных консоли, но когда выполняется обратный вызов и вы регистрируете «геокодировано ...» , вы увидите только AddressObject в том виде, в каком он существовал после последней итерации цикла, потому что цикл завершился давно (это характерно для асинхронного JavaScript).

Способ решить вашу проблему - передавать каждый вызов srPerformGeocode копии массива AddressObject. Для удобства массивы имеют метод, возвращающий новый массив slice . (splice только изменяет массив, но не создает новый.)

for (var i = 0; i < AddressObject.addressToArray.length; i++) {              
 srPerformGeocode(AddressObject.slice(0, -i));
}

(Обратите внимание, что это неглубокая копия; то есть любые объекты в массиве по-прежнему указывают на те же объекты, что и исходный массив. Здесь это не имеет значения, поскольку ваш массив полон примитивов.)

Некоторые другие примечания:

  1. String.trim не существует в IE 8, поэтому ваш вызов address.trim() вызовет исключение.
  2. Карты Google на самом деле не выполняют массовое геокодирование; вы можете столкнуться с ограничением скорости или даже полным отключением, если сделаете слишком много вызовов геокодирования.

1 Педанты не согласятся с этим утверждением; см. связанный ответ.

person josh3736    schedule 31.01.2012

В то время, когда ваш обратный вызов вызывается API геокодирования, AddressObject.addressToArray был изменен. Лучше держаться за переданную строку (а не за объект).

Я подозреваю, что это даст вам желаемый результат:

console.log("geocoded " + address.trim());
person Timothy Jones    schedule 31.01.2012