在循环中使用JQuery Ajax延迟

在循环中使用JQuery Ajax延迟,jquery,ajax,loops,deferred,Jquery,Ajax,Loops,Deferred,我需要通过REST将许多项传递给API。我需要循环一组项目,并将每个项目激发到远程API。目的是在每次调用API之间等待成功 这是我目前尝试使用JQuery的承诺: items.each(function(model) { $.when(addItem(model,endpoint)).done(function(data, xhr, results) { console.log('added'); }); Ajax调用如下所示: addItem: functi

我需要通过REST将许多项传递给API。我需要循环一组项目,并将每个项目激发到远程API。目的是在每次调用API之间等待成功

这是我目前尝试使用JQuery的承诺:

items.each(function(model) {
    $.when(addItem(model,endpoint)).done(function(data, xhr, results) {
        console.log('added');
  });
Ajax调用如下所示:

  addItem: function(model, endpoint) {
    return $.ajax({
      url: 'http://api' + endpoint,
      type: "POST",
      headers: {
        "accept":"application/json"
      },
      dataType: "json",
      data: {
        item: model.attributes.id,
        amount: model.attributes.amount
      }
    });
  }
};
当代码在循环中多次运行时,我会存储一些项,一些返回500响应,一些返回409(重复)响应。我可以毫无问题地手动将这些项添加到API中。这可能只是因为循环对于API来说运行得太快了,但也可能是我的代码。我知道有更好的方法来添加这些项,但目前我不得不使用这个循环思想进行测试,直到API代码的未来迭代


上述内容看起来正确吗,或者有更好的方法解决这个问题吗?

您可以通过在AJAX调用成功时递归调用来链接AJAX调用,或者可以使调用同步(通过使用
async:false
):


请注意,同步将阻止任何其他Javascript运行,因为Javascript是单线程的

您应该能够在延迟回调中小心地使用递归,按顺序附加回调。下面是一个可能的实现:

// I'm paranoid about making sure basic prototype functions are available
// even if some library clobbers the original definition later.
var slice = Array.prototype.slice;

// This function should be `.apply`'d with the array of models you need to add.
// It will call `addItem` on the first argument, and then use this function as
// a callback to `addItem` with the arguments shifted by one.
var invokeAddItem = function (modelToAdd) {
    var rest = slice.call(arguments, 1);

    addItem(modelToAdd, endpoint).always(function () {
        invokeAddItem.apply(null, rest);
    });
};

invokeAddItem.apply(null, items);    // Equivalent to `invokeAddItem(items[0], ...)`

我建议将回调函数传递给additem/ajax调用,而不是在时尝试执行
,但我很好奇其他人会怎么说…@cale\u b:这可能是最好的方法。棘手的部分来自于以异步方式迭代模型。我的答案是使用
jQuery.Deferred#始终
,而不是传入回调,但我认为它或多或少符合您所理解的精神。
// I'm paranoid about making sure basic prototype functions are available
// even if some library clobbers the original definition later.
var slice = Array.prototype.slice;

// This function should be `.apply`'d with the array of models you need to add.
// It will call `addItem` on the first argument, and then use this function as
// a callback to `addItem` with the arguments shifted by one.
var invokeAddItem = function (modelToAdd) {
    var rest = slice.call(arguments, 1);

    addItem(modelToAdd, endpoint).always(function () {
        invokeAddItem.apply(null, rest);
    });
};

invokeAddItem.apply(null, items);    // Equivalent to `invokeAddItem(items[0], ...)`