(为什么)这个ajax队列会覆盖响应数据吗?

时间:2011-03-01 11:49:42

标签: javascript jquery

我使用此处发布的ajax-request队列:Wait until all jQuery Ajax requests are done?

现在我编写了以下代码来实现它:

for (var i=0; i<3; i++) {
    $.ajaxQueue({
        url: '/action/',
        data: {action:'previous',item:i*-1},
        type: 'GET',
        success: function(data) {
            $('.item-history .itemlist').prepend(data['item_add']);
            $('.item-history .itemlist:first .index').html(data['newitemindex']);
            //alert(data['newitemindex'])       
        };
    });

只要我使用警报来证明来自服务器的响应,一切正常。但是一旦我运行代码,如图所示,没有警报,data ['newitemindex']就像它是一个全局变量一样 - 它总是返回最后一项的值。

我试图在此设置一个jsfiddle,但由于我从未使用过那个网站,我无法让ajax工作。如果有人想看一下它:http://jsfiddle.net/marue/UfH5M/26/

1 个答案:

答案 0 :(得分:3)

您的代码正在设置三个ajax调用,然后将每个调用的结果应用于相同的元素(您在success函数中使用的选择器没有区别) 。对于$('.item-history .itemlist')元素,您应该看到每个调用前置的结果,因为您使用的是prepend(),但对于$('.item-history .itemlist:first .index')元素,您'使用html() 替换元素的内容,因此对于那些你会看到完成的最后一次调用的结果。


偏离主题:要解决此问题,您可能希望在success函数中以某种方式使用循环变量。这可能会导致一个常见的错误,所以这里有一个错误的例子,以及如何避免错误。

假设我有这些div:

<div id='div1'></div>
<div id='div2'></div>
<div id='div3'></div>

当我点击按钮时,我想使用三个ajax调用来填充它们,使用从13的循环计数器。我想我可以这样做:

$('#btnGo').click(function() {
  var i;

  for (i = 1; i <= 3; ++i) {
    $.ajax({
      url: "/agiba4/" + i,
      dataType: "text",
      success: function(data) {
        // THIS NEXT LINE IS WRONG
        $('#div' + i).html(data);
      },
      error: function(xhr, status, err) {
        $("<p/>").html(
          "Error, status = " + status + ", err = " + err
          ).appendTo(document.body);
      }
    });
  }
});

Live example (失败)

但是(如图所示)不起作用。它不起作用,因为我们创建的每个success函数都有{em>持久引用到i变量,它的值的副本何时创建success函数。因此,所有三个success函数都会看到i的相同值,这是函数运行时的值 - 在循环完成后很久。所以(在这个例子中),它们都看到值4(循环结束后i的值)。这就是闭包的工作方式(参见:Closures are not complicated)。

要解决此问题,请对其进行设置,以便success函数关闭不会被循环更新的内容。最简单的方法是将循环计数器作为参数传递给另一个函数,然后让success函数关闭该参数,因为参数是循环计数器的 copy ,将不会更新:

$('#btnGo').click(function() {
  var i;

  for (i = 1; i <= 3; ++i) {
    doRequest(i);
  }

  function doRequest(index) {
    $.ajax({
      url: "/agiba4/" + index,
      dataType: "text",
      success: function(data) {
        $('#div' + index).html(data);
      },
      error: function(xhr, status, err) {
        $("<p/>").html(
          "Error, status = " + status + ", err = " + err
          ).appendTo(document.body);
      }
    });
  }
});

Live example