我有一个简单的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");
});
这应输出..
然后results
数组包含所有3个ajax请求的结果。这可能吗?
答案 0 :(得分:8)
首先,您必须决定是否要并行处理三个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")
});
因为您在等待.done()
$.when()
$.when()
处理程序之前等待,所有ajax结果都会立即就绪,并按results
按顺序显示被要求(无论哪一个实际上先完成),所以你尽可能快地得到结果,并以可预测的顺序呈现。
注意,我还将$.when()
数组的定义移到了.map()
完成的处理程序中,因为这是您知道数据实际有效的唯一地方(出于时间原因)。 / p>
并行运行 - 迭代任意长度数组
如果你有一个更长的数组,你可能会发现用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
});
之类的方法迭代你的数组更好地在循环中处理它们而不是单独列出它们:
$.when()
对Ajax调用进行排序
另一方面,如果你真的想要对你的ajax调用进行排序,那么第二个调用就不会开始直到第一个调用完成(如果第二个ajax调用需要来自第一个ajax的结果,那么可能需要这样做)为了知道要求或做什么而打电话,那么你需要一个完全不同的设计模式,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
控制台输出:
results
如果您的文件数组较长,也可以将此结构放入循环中以自动运行N个连续的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");
});
数组。
请注意,承诺在此提供的优势在于,您可以在保持同一顶层嵌套的同时对操作进行排序,而不会进一步嵌套。
对Ajax调用进行排序 - 迭代任意长度数组
这里的顺序是循环中的顺序:
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()
迭代开始时带有.then()
的空/已解决的承诺(还有其他方法也可以创建这样的承诺),它只是让我们开始做{{1}}就已经开始了解决。
答案 1 :(得分:2)
您应该从.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的参数将与传递给它们的顺序相同。当
时