JavaScript - геокод Google - проблема закрытия / зацикливания - PullRequest
2 голосов
/ 31 января 2012

Я несколько раз вызываю функцию 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

Ответы [ 2 ]

1 голос
/ 31 января 2012

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

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

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

Способ решения вашей проблемы - передать каждый вызов srPerformGeocode a copy массива AddressObject. Удобно, чтобы у массивов был метод, который возвращает новый массив & ndash; slice. (splice только изменяет массив; он не создает новый.)

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

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

Некоторые другие заметки:

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

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

0 голосов
/ 31 января 2012

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

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

console.log("geocoded " + address.trim());
...