jQuery,带有url数组的$ .ajax

我有一个简单的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"); }); 

这应该输出..

  • 步骤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() 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 }); 

对Ajax调用进行排序

另一方面,如果你真的想要对你的ajax调用进行排序,那么第二个调用就不会开始,直到第一个调用完成(如果第二个ajax调用需要来自第一个ajax调用的结果才能知道,这可能是必需的请求或做什么,然后你需要一个完全不同的设计模式和$.when()根本不是什么方式(它只做并行请求)。 在这种情况下,您可能只想用x.then().then()链接结果, 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数组。

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


对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()就已经是解决。

您应该从.then而不是每个.done访问返回值。 另外, .map是你的朋友。

 var results = [], files = [ 'url1', 'url2', 'url3' ]; $.when.apply($, $.map(files, function (file) { return $.ajax(file); })).then(function (dataArr) { /* * dataArr is an array of arrays, * each array contains the arguments * returned to each success callback */ results = $.map(dataArr, function (data) { return data[0]; // the first argument to the success callback is the data }); console.log(results); }); 

传递给.then的参数将与传递给它们的顺序相同