jQuery使用.when并推送一个数组

时间:2013-11-08 12:11:57

标签: javascript jquery ajax asynchronous .when

一直在考虑使用ajax()获取$.when个回复的回调我仍然不确定这是如何完全有效的,但这是我希望以下做的事情。

当用户每行添加一个城镇和国家/地区时,它会转到.ajax()中的网址我收到回复并推送该数组以便在.each()循环之外使用。

目前您将在 here at 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 个答案:

答案 0 :(得分:5)

您没有正确使用$.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);
    });
});

这里有几点需要注意:

  1. 返回一系列独立承诺意味着您无法直接将它们提供给$.when,因为该函数旨在接受多个单独的承诺而不是数组;您需要使用apply进行补偿。
  2. 我在click事件处理程序中移动了arrayLocation的声明,以便每次单击按钮时都会重置它。每次点击后再次添加结果的问题是由于此数组未被重置。
  3. 最终处理程序不接受任何参数。那是因为将传递的参数是表示各个AJAX请求的jqXHR对象,这些对象并不实用。而不是通过闭包捕获arrayLocation,因为您独立知道结果将存储在那里。

答案 1 :(得分:0)

没有共享全局变量的略有不同的方法

$('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)
    })
});

演示:Fiddle