我需要在不锁定浏览器的情况下发出一系列 N 个 ajax 请求,并希望使用 jquery 延迟对象来完成此操作。
这是一个包含三个请求的简化示例,但我的程序可能需要排队超过 100 个(请注意,这不是确切的用例,实际代码确实需要确保之前步骤(N-1)成功执行下一步):
$(document).ready(function(){
var deferred = $.Deferred();
var countries = ["US", "CA", "MX"];
$.each(countries, function(index, country){
deferred.pipe(getData(country));
});
});
function getData(country){
var data = {
"country": country
};
console.log("Making request for [" + country + "]");
return $.ajax({
type: "POST",
url: "ajax.jsp",
data: data,
dataType: "JSON",
success: function(){
console.log("Successful request for [" + country + "]");
}
});
}
以下是写入控制台的内容(所有请求都是并行发出的,响应时间与预期的每个国家/地区的数据大小成正比:
Making request for [US]
Making request for [CA]
Making request for [MX]
Successful request for [MX]
Successful request for [CA]
Successful request for [US]
如何让延迟对象为我排队?我尝试将 did 更改为管道,但得到相同的结果。
这是期望的结果:
Making request for [US]
Successful request for [US]
Making request for [CA]
Successful request for [CA]
Making request for [MX]
Successful request for [MX]
编辑:
我很欣赏使用数组来存储请求参数的建议,但是 jquery 延迟对象具有对请求进行排队的能力,我真的很想了解如何充分利用此功能。
这实际上就是我正在尝试做的事情:
when(request[0]).pipe(request[1]).pipe(request[2])... pipe(request[N]);
但是,我想一次一步地将请求分配到管道中,以便有效地使用每次遍历:
deferred.pipe(request[0]);
deferred.pipe(request[1]);
deferred.pipe(request[2]);
最佳答案
使用自定义对象
function DeferredAjax(opts) {
this.options=opts;
this.deferred=$.Deferred();
this.country=opts.country;
}
DeferredAjax.prototype.invoke=function() {
var self=this, data={country:self.country};
console.log("Making request for [" + self.country + "]");
return $.ajax({
type: "GET",
url: "wait.php",
data: data,
dataType: "JSON",
success: function(){
console.log("Successful request for [" + self.country + "]");
self.deferred.resolve();
}
});
};
DeferredAjax.prototype.promise=function() {
return this.deferred.promise();
};
var countries = ["US", "CA", "MX"], startingpoint = $.Deferred();
startingpoint.resolve();
$.each(countries, function(ix, country) {
var da = new DeferredAjax({
country: country
});
$.when(startingpoint ).then(function() {
da.invoke();
});
startingpoint= da;
});
fiddle http://jsfiddle.net/7kuX9/1/
为了更清楚一点,可以写最后几行
c1=new DeferredAjax( {country:"US"} );
c2=new DeferredAjax( {country:"CA"} );
c3=new DeferredAjax( {country:"MX"} );
$.when( c1 ).then( function() {c2.invoke();} );
$.when( c2 ).then( function() {c3.invoke();} );
带管道
function fireRequest(country) {
return $.ajax({
type: "GET",
url: "wait.php",
data: {country:country},
dataType: "JSON",
success: function(){
console.log("Successful request for [" + country + "]");
}
});
}
var countries=["US","CA","MX"], startingpoint=$.Deferred();
startingpoint.resolve();
$.each(countries,function(ix,country) {
startingpoint=startingpoint.pipe( function() {
console.log("Making request for [" + country + "]");
return fireRequest(country);
});
});
编辑:在结果窗口中输出日志的 fiddle http://jsfiddle.net/k8aUj/3/
每个管道调用都会返回一个新的 Promise,该 promise 又用于下一个管道。请注意,我只提供了 sccess 函数,对于失败应该提供类似的函数。
在每个解决方案中,Ajax 调用都会被延迟到需要时为止,方法是将它们包装在一个函数中,并为列表中的每个项目创建一个新的 Promise 以构建链。
我相信自定义对象提供了一种更简单的方法来操纵链,但管道可能更适合您的口味。
注意:从 jQuery 1.8 开始,deferred.pipe()
已弃用,deferred.then
替换它。
关于jquery - 如何使用 jquery 链接 ajax 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8612894/