我需要发出一系列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]
我怎样才能让延期的对象为我排队呢?我试过更改完成管道,但得到相同的结果。
这是期望的结果:
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; });
小提琴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); }); });
http://jsfiddle.net/k8aUj/1/
编辑:在结果窗口中输出日志的小提琴http://jsfiddle.net/k8aUj/3/
每个管道调用都返回一个新的Promise,该诺言又用于下一个管道。请注意,我仅提供了sccess功能,应该为失败提供类似的功能。
在每种解决方案中,通过将Ajax调用包装到一个函数中来延迟它们,直到需要使用为止,并为列表中的每个项目创建一个新的Promise以构建链。
我相信自定义对象提供了一种操作链的简便方法,但是管道可以更好地适合您的口味。
注意 :从jQuery 1.8开始,deferred.pipe()不推荐使用,deferred.then将其替换。
deferred.pipe()
deferred.then