0

我有一个对象数组,我试图对其进行迭代并为列表构建标记。我正在使用一个数组来存储延迟的请求,并在所有请求完成后使用 $.when 将连接的标记注入到 DOM 中。

这是代码:

function populateItemList(items) {
  var output = '',
    item = null,
    template = null,
    defers = [];

  for (var i = 0, j = items.length; i < j; i++) {
    item = items[i];

    defers.push(function() {
      $.get('/item/' + item.id + '/template')
      .done(function(source) {
        template = Handlebars.compile(source);
        output += template(item);

        console.log(item.id + ': done');
      })
    });
  }

  $.when.apply(window, defers).done(function() {
    $('.itemListContainer').html(output);
    $('.itemList a').click(onItemLinkClick);

    console.log('when: ' + output);
  });
}

但是,我没有任何成功。我遇到了两个问题之一:

  1. 如果我确实将延迟项目包装在一个函数中(如上面的代码中所示),则不会执行请求,但 $.when会执行。但是由于请求没有被执行,所以输出是空的。
  2. 如果我将延迟项目包装在函数中,则请求会被执行(正确的次数,但记录到控制台的 item.id 始终是最后一个项目的 id),而 $.when不会被执行。

我知道这与这个问题非常相似,我正在使用该代码作为我的基础,但我仍然遇到这些问题。有任何想法吗?

4

1 回答 1

2

当您将代码包装在这样的函数中时,代码永远不会被执行。您推入数组的是对函数的引用,而不是 AJAX 调用的结果。

当您不将代码包装在一个函数中时,它确实会被执行,但是当您item在回调中使用局部变量时,您将使用该变量在响应到达时所具有的值,而不是在请求时寄了,送了。populateItemList由于请求是异步的,并且由于 Javascript 是单线程的,因此在您从函数返回之前不会调用回调,因此item变量将始终是最后一项。

您应该将代码包装在一个函数中,这样您就可item以为每次迭代创建一个变量,但您也应该立即执行该函数,并将返回值推送到数组中:

for (var i = 0, j = items.length; i < j; i++) {

  var result = (function(item) {
    return $.get('/item/' + item.id + '/template')
    .done(function(source) {
      template = Handlebars.compile(source);
      output += template(item);
      console.log(item.id + ': done');
    });
  }(items[i]));

  defers.push(result);
}
于 2013-02-01T20:28:55.017 回答