我需要做一系列N ajax请求,而不锁定浏览器,并希望使用jquery deferred对象来完成这个。
这里是一个简单的例子,有三个请求,但我的程序可能需要排队超过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]
如何获得延迟对象排队这些为我?我试过更改完成管,但得到相同的结果。
这里是所需的结果:
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 deferred对象有排队请求的能力,我真的想学习如何使用这个功能的全部潜力。
这实际上是我想做的:
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",success: function(){ console.log("Successful request for [" + self.country + "]"); self.deferred.resolve(); } }); }; DeferredAjax.prototype.promise=function() { return this.deferred.promise(); }; var countries = ["US","MX"],startingpoint = $.Deferred(); startingpoint.resolve(); $.each(countries,function(ix,country) { var da = new DeferredAjax({ country: country }); $.when(startingpoint ).then(function() { da.invoke(); }); startingpoint= da; });
小提琴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",data: {country:country},success: function(){ console.log("Successful request for [" + country + "]"); } }); } var countries=["US",startingpoint=$.Deferred(); startingpoint.resolve(); $.each(countries,country) { startingpoint=startingpoint.pipe( function() { console.log("Making request for [" + country + "]"); return fireRequest(country); }); });
编辑:在结果窗口http://jsfiddle.net/k8aUj/3/中输出日志的小提琴
每个管道调用返回一个新的promise,它又用于下一个管道。注意,我只提供sccess功能,应该提供类似的功能失败。
在每个解决方案中,Ajax调用被延迟,直到需要通过将它们包装在一个函数中,并为列表中的每个项目创建一个新的promise来构建链。
我相信自定义对象提供了一个更容易的方式来操纵链,但管道可以更好地适合你的口味。
注意:作为jQuery 1.8,deferred.pipe()
已弃用,deferred.then
替换它。