Gra*_*ham 33 ajax jquery deferred jquery-deferred
我需要在不锁定浏览器的情况下发出一系列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 + "]");
}
});
}
Run Code Online (Sandbox Code Playgroud)
这是写入控制台的内容(所有请求都是并行进行的,响应时间与每个国家/地区的数据大小成正比:
Making request for [US]
Making request for [CA]
Making request for [MX]
Successful request for [MX]
Successful request for [CA]
Successful request for [US]
Run Code Online (Sandbox Code Playgroud)
我怎样才能让延迟对象为我排队?我已经尝试将完成更改为管道,但得到相同的结果.
这是期望的结果:
Making request for [US]
Successful request for [US]
Making request for [CA]
Successful request for [CA]
Making request for [MX]
Successful request for [MX]
Run Code Online (Sandbox Code Playgroud)
编辑:
我很欣赏使用数组来存储请求参数的建议,但是jquery延迟对象能够对请求进行排队,我真的想学习如何充分利用这个功能.
这实际上是我想要做的:
when(request[0]).pipe(request[1]).pipe(request[2])... pipe(request[N]);
Run Code Online (Sandbox Code Playgroud)
但是,我想一次一步地将请求分配到管道中,以便有效地使用每个遍历:
deferred.pipe(request[0]);
deferred.pipe(request[1]);
deferred.pipe(request[2]);
Run Code Online (Sandbox Code Playgroud)
nik*_*shr 31
使用自定义对象
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;
});
Run Code Online (Sandbox Code Playgroud)
小提琴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();} );
Run Code Online (Sandbox Code Playgroud)
用管子
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);
});
});
Run Code Online (Sandbox Code Playgroud)
编辑:在结果窗口输出日志的小提琴http://jsfiddle.net/k8aUj/3/
每个管道调用都返回一个新的promise,该promise又用于下一个管道.请注意,我只提供了sccess函数,应该为失败提供类似的功能.
在每个解决方案中,Ajax调用都会延迟到需要时将它们包装在一个函数中,并为列表中的每个项创建一个新的promise以构建链.
我相信自定义对象提供了一种更简单的操作链的方法,但管道可以更好地满足您的口味.
注意:从jQuery 1.8开始,deferred.pipe()不推荐deferred.then使用它,替换它.
注意:从jquery 1.8开始,您可以使用.then而不是.pipe.该.then函数现在返回一个新的promise,.pipe因为不再需要它而被弃用.有关promises的更多信息,请参阅promises规范 ; 如果没有jquery依赖关系,请参阅q.js以获得更清晰的javascript承诺库.
countries.reduce(function(l, r){
return l.then(function(){return getData(r)});
}, $.Deferred().resolve());
Run Code Online (Sandbox Code Playgroud)
如果你想使用q.js:
//create a closure for each call
function getCountry(c){return function(){return getData(c)};}
//fire the closures one by one
//note: in Q, when(p1,f1) is the static version of p1.then(f1)
countries.map(getCountry).reduce(Q.when, Q());
Run Code Online (Sandbox Code Playgroud)
原始答案:
还有另一根烟斗; 不是为了胆小的人,而是为了更紧凑:
countries.reduce(function(l, r){
return l.pipe(function(){return getData(r)});
}, $.Deferred().resolve());
Run Code Online (Sandbox Code Playgroud)
减少文档可能是开始理解上述代码如何工作的最佳位置.基本上,它需要两个参数,一个回调和一个初始值.
回调迭代地应用于数组的所有元素,其中第一个参数是前一次迭代的结果,第二个参数是当前元素.这里的技巧是getData()返回一个jquery延迟的promise,并且管道确保在当前元素上调用getData之前完成前一个元素的getData.
第二个参数$.Deferred().resolve()是已解决的延迟值的惯用语.它被送到回调执行的第一次迭代,并确保立即调用第一个元素上的getData.
| 归档时间: |
|
| 查看次数: |
29783 次 |
| 最近记录: |