JQuery, используя.when и толкая массив
Были в поиске обратных вызовов для ajax()
ответы с использованием $.when
Я все еще не уверен, как это работает полностью, но это то, что я хотел бы сделать ниже.
Когда пользователь добавляет город и страну в строке, он переходит на URL в .ajax()
Я получаю ответ, и он толкает массив для использования за пределами .each()
петля.
На данный момент вы увидите здесь, на jsbin, что когда button
сначала нажимается ответ в console.log []
затем, когда я нажимаю его снова, адреса появляются. затем третье нажатие снова добавит адреса, чего не должно быть.
JQuery
var addresses,town;
var arrayLocation = [];
$('button').click(function(){
addresses = function() {
deferred = new $.Deferred();
var arrayOfLines = $('#gps').val().split('\n');
$.each(arrayOfLines, function(index, item) {
town = item.split(',');
$.ajax({
url: 'http://maps.googleapis.com/maps/api/geocode/json?address='+town[0]+'&sensor=false',
dataType: 'json',
success: function (data) {
add = data.results[0].address_components[0].long_name;
lat = data.results[0].geometry.location.lat;
lng = data.results[0].geometry.location.lng;
arrayLocation.push("['"+add+"', "+lat+", "+lng+"]");
console.log("['"+add+"', "+lat+", "+lng+"]");
}
});
});
return arrayLocation;
};
$.when(addresses()).then(function(arrayLocation){
console.log(arrayLocation);
});
});
2 ответа
Вы не используете $.when
правильно. Основная проблема заключается в том, что addresses
Функция возвращает пустой массив. Это правда, что этот массив будет заполнен в будущем, когда асинхронная операция (набор вызовов AJAX) завершится, но с точки зрения addresses
Абоненту это невозможно узнать. Поэтому у звонящего абсолютно нет шансов отреагировать на завершающуюся операцию.
Что вы обычно делаете, это вернуть возвращаемое значение $.ajax
звонящему, примерно так:
addresses = function() {
return $.ajax({ ... });
};
Звонивший мог тогда сделать
$.when(addresses()).then(function(result) { ... });
Однако в этом конкретном примере это невозможно сделать напрямую, поскольку выполняется несколько вызовов AJAX, поэтому вам нужен какой-то способ "объединить" их все в один пакет. Есть несколько способов сделать это, поэтому есть вопрос, что вы предпочитаете здесь.
Одним из решений будет использование массива обещаний AJAX:
$('button').click(function(){
var arrayLocation = [];
addresses = function() {
var promises = [];
var arrayOfLines = $('#gps').val().split('\n');
$.each(arrayOfLines, function(index, item) {
town = item.split(',');
promises.push($.ajax({
url: 'http://maps.googleapis.com/...',
dataType: 'json',
success: function (data) {
add = data.results[0].address_components[0].long_name;
lat = data.results[0].geometry.location.lat;
lng = data.results[0].geometry.location.lng;
arrayLocation.push("['"+add+"', "+lat+", "+lng+"]");
console.log("['"+add+"', "+lat+", "+lng+"]");
}
}));
});
return promises;
};
$.when.apply($, addresses()).then(function(){
console.log(arrayLocation);
});
});
Здесь есть пара замечаний:
- Возвращение массива независимых обещаний означает, что вы не можете передать их
$.when
непосредственно, потому что эта функция предназначена для принятия нескольких отдельных обещаний вместо массива; вам нужно использоватьapply
компенсировать. - Я перенес декларацию
arrayLocation
внутри обработчика события click, чтобы он сбрасывался при каждом нажатии кнопки. Проблема результатов, добавляемых снова после каждого клика, была связана с тем, что этот массив не сбрасывался. - Последний обработчик не принимает никаких аргументов. Это потому, что аргументы, которые будут переданы, являются объектами jqXHR, представляющими отдельные запросы AJAX, что не очень полезно. Вместо этого он захватывает
arrayLocation
закрытием, так как вы независимо знаете, что результаты будут храниться там.
Немного другой подход без общих глобальных переменных
$('button').click(function () {
var addresses = function () {
var arrayOfLines = $('#gps').val().split('\n'),
arrayLocation = [];
$.each(arrayOfLines, function (index, item) {
var town = item.split(',');
var xhr = $.ajax({
url: 'http://maps.googleapis.com/maps/api/geocode/json?address=' + $.trim(town[0]) + '&sensor=false',
dataType: 'json'
});
arrayLocation.push(xhr);
});
return $.when.apply($, arrayLocation).then(function () {
return $.map(arguments, function (args) {
if (!$.isArray(args[0].results) || args[0].results.length == 0) {
return undefined;
}
var data = args[0].results[0];
var location = data.geometry.location;
var add = data.address_components[0].long_name;
var lat = location.lat;
var lng = lng;
return "['" + add + "', " + lat + ", " + lng + "]";
});
});
return arrayLocation;
};
addresses().done(function (arrayLocation) {
console.log(arrayLocation)
})
});
Демо: скрипка