jQuery,带有url数组的$ .ajax

Cie*_*iel 11 arrays ajax jquery promise jquery-deferred

我有一个简单的url数组,我想用jQuery加载每一个.我正在使用$.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");
});
Run Code Online (Sandbox Code Playgroud)

这应该输出..

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

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

jfr*_*d00 9

首先,您必须决定是否要并行处理三个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")
});
Run Code Online (Sandbox Code Playgroud)

因为你等待调用.done()处理程序$.when(),所以所有的ajax结果都会立即就绪,它们$.when()按照它们被请求的顺序显示(无论哪一个实际先完成),所以你得到的结果就像可能,它们以可预测的顺序呈现.

注意,我还将results数组的定义移动到$.when()done处理程序中,因为这是您知道数据实际有效的唯一位置(出于计时原因).


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

如果你有一个更长的数组,你可能会发现更好地迭代你的数组,比如.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
});
Run Code Online (Sandbox Code Playgroud)

对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");
  });
Run Code Online (Sandbox Code Playgroud)

控制台输出:

step 1.0
step 1.1
step 1.2
step 2
Run Code Online (Sandbox Code Playgroud)

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

请注意,承诺在此提供的优势在于,您可以在保持相同的嵌套顶级水平的同时对操作进行排序,而不会进一步嵌套.


对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");
});
Run Code Online (Sandbox Code Playgroud)

控制台输出:

step 1.0
step 1.1
step 1.2
step 1.3
step 1.4
step 1.5
step 1.6
step 2
Run Code Online (Sandbox Code Playgroud)

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