jQuery、$.ajax 和 url 数组

标签 jquery ajax arrays promise jquery-deferred

我有一个简单的 URL 数组,我想用 jQuery 加载每个 URL。我正在使用 $.get,但我似乎无法让它与 $.Deferred 一起使用,所以我切换到 $.ajax -我几乎让它工作了,但我得到的结果是......奇怪的。我希望有人能帮助我把这项工作做得更好。

var results = [], files = [
   'url1', 'url2', 'url3'
];

$.when(
   $.ajax(files[0]).done(function(data) { 
      results.push(data); console.log("step 1.0"); 
   }),
   $.ajax(files[1]).done(function(data) { 
      results.push(data); console.log("step 1.1"); 
   }),
   $.ajax(files[2]).done(function(data) {
      results.push(data); console.log("step 1.2"); 
   })
).then(function(){
   console.log("step 2");
});

这应该输出..

  • 步骤 1.0
  • 步骤1.1
  • 步骤 1.2
  • 第 2 步

然后 results 数组包含所有 3 个 ajax 请求的结果。这可能吗?

最佳答案

首先,您必须决定是否希望并行处理三个 ajax 调用(全部同时运行,总体运行时间较短),还是按顺序处理一个 ajax 调用,先运行、完成,然后启动下一个ajax调用。这是一个关键的设计决策,会影响您的操作方式。

当您使用$.when()时,您将并行启动所有三个ajax调用。如果您仅在所有结果都完成后才检查结果,您仍然可以按特定顺序处理结果(因为只有当所有结果都可用并且它们将按请求的顺序可用时,您才会处理它们)。但是,当这样做时,所有 ajax 调用最初都会立即发送。这将为您提供更好的端到端时间,因此如果这对于请求类型可行,那么这通常是更好的方法。

为此,您可以将现有内容重组为如下所示:

并行运行

var files = [
   'url1', 'url2', 'url3'
];

$.when($.ajax(files[0]),$.ajax(files[1]),$.ajax(files[2])).done(function(a1, a2, a3) {
   var results = [];
   results.push(a1[0]);
   results.push(a2[0]);
   results.push(a3[0]);
   console.log("got all results")
});

因为您正在等待 $.when().done() 处理程序被调用,所以所有 ajax 结果立即准备就绪,并且由 $.when() 按照请求的顺序呈现(无论哪一个实际首先完成),因此您可以尽快获得结果,并且它们会以可预测的顺序呈现。

注意,我还将 results 数组的定义移至 $.when() did 处理程序中,因为这是您知道数据实际上有效的唯一位置(由于时间原因)。

<小时/>

并行运行 - 迭代任意长度数组

如果您有一个较长的数组,您可能会发现最好使用 .map() 之类的方法迭代数组,以循环处理它们,而不是单独列出它们:

var files = [
   'url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7'
];

$.when.apply($, files.map(function(url) {
    return $.ajax(url);
})).done(function() {
    var results = [];
    // there will be one argument passed to this callback for each ajax call
    // each argument is of this form [data, statusText, jqXHR]
    for (var i = 0; i < arguments.length; i++) {
        results.push(arguments[i][0]);
    }
    // all data is now in the results array in order
});
<小时/>

对 Ajax 调用进行排序

另一方面,如果您确实想要对 ajax 调用进行排序,以便在第一个 ajax 调用完成之前第二个调用不会开始(如果第二个 ajax 调用需要第一个 ajax 调用的结果,则可能需要这样做)为了知道要请求什么或做什么),那么您需要一个完全不同的设计模式,而 $.when() 根本不是可行的方法(它只执行并行请求)。在这种情况下,您可能只想将结果与 x.then().then() 链接起来,然后您可以按照您要求的顺序输出日志语句,如下所示。

  $.ajax(files[0]).then(function(data0) {
      console.log("step 1.0");
      return $.ajax(files[1]);
  }).then(function(data1) {
      console.log("step 1.1");
      return $.ajax(files[2]);
  }).done(function(data2) {
      console.log("step 1.2");
      // all the ajax calls are done here
      console.log("step 2");
  });

控制台输出:

step 1.0
step 1.1
step 1.2
step 2

如果你的文件数组较长,这个结构也可以放入循环中,自动运行 N 个连续的 ajax 调用。虽然您可以在进入 results 数组时收集结果,但通常按顺序完成操作的原因是先前的结果会被下一个 ajax 调用消耗,因此您通常只需要最终结果。如果您想随时收集结果,您当然可以在每一步将它们推送到 results 数组中。

请注意,Promise 在这里提供的优势在于,您可以对操作进行排序,同时保持相同的嵌套顶层,而不会越来越嵌套。

<小时/>

对 Ajax 调用进行排序 - 迭代任意长度数组

这是循环中的排序的样子:

var files = [
   'url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7'
];

var results = [];
files.reduce(function(prev, cur, index) {
    return prev.then(function(data) {
        return $.ajax(cur).then(function(data) {
            console.log("step 1." + index);
            results.push(data);
        });
    })
}, $().promise()).done(function() {
    // last ajax call done
    // all results are in the results array
    console.log("step 2.0");
});

控制台输出:

step 1.0
step 1.1
step 1.2
step 1.3
step 1.4
step 1.5
step 1.6
step 2

Array.prototype.reduce() 方法在这里可以很方便地工作,因为当您处理每个单独的数组元素时,它会累积单个值,这就是您在添加 时需要执行的操作。then () 对于每个数组元素。 .reduce() 迭代是用 $().promise() 的空/已解决的 Promise 开始的(还有其他方法也可以创建这样的 Promise),这只是给我们一些东西来开始做 .then() 已经解决的问题。

关于jQuery、$.ajax 和 url 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24705401/

相关文章:

javascript - JS 无法从数组填充数组

javascript - jquery/js,从textfield中获取一个值并使用ajax将其发送到服务器

jquery - Django:注册期间有效/可用的用户名/电子邮件的ajax响应

jquery - 无法在 LINQ to Entities 查询中构造实体或复杂类型 'OdeToFood.Models.RestaurantListViewModel'

javascript - 如何在 javascript 调用后重新加载样式?

mysql - 循环并将值插入到mysql中的表中

asp.net-mvc - 使用 jQuery POST 和 ASP.NET MVC 时 Controller 参数为 NULL

javascript - 如何加载图像文件,每个文件到自己的 Canvas 元素中

php - jQuery AJAX 调用两次

c - 如何定义一个字符串数组,分配与定义分开?