首先,您需要决定您是否希望您的三个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()
的处理程序中,因为那是您知道数据实际上有效的唯一位置(由于时间原因)。
并行运行 - 迭代任意长度数组
如果您有一个更长的数组,您可能会发现使用像.map()
这样的东西迭代遍历整个数组以在循环中处理它们比单独列出它们要好:
var files = [
'url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7'
];
$.when.apply($, files.map(function(url) {
return $.ajax(url);
})).done(function() {
var results = [];
for (var i = 0; i < arguments.length; i++) {
results.push(arguments[i][0]);
}
});
按顺序执行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");
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() {
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()
时需要做的。使用$().promise()
创建一个空/已解决的Promise(也有其他方法可以创建这样的Promise),.reduce()
迭代从此开始,这仅给我们提供了一个已经解决并且可以开始使用.then()
的东西。
步骤1.2、步骤1.0、步骤1.1、步骤2
,但数组总是在执行then()
之前被填充。 - Rory McCrossanseries
或者eachSeries
方法。 - Mike