当多个Deferred对象传递给jQuery.when时,该方法从一个新的"master"Deferred对象返回Promise,该对象跟踪它已经传递的所有Deferred的聚合状态.
该方法将
一旦所有Deferred解决,就解决它的主延期,或者
拒绝其主人一旦被拒绝一个延期,就拒绝延期.
如果主Deferred被解析(即所有Deferreds解析),则传递给传递给jQuery.when的所有Deferred的已解析值.例如,当Deferreds是jQuery.ajax()请求时,参数将是请求的jqXHR对象,按照它们在参数列表中给出的顺序:
$.when( $.getJSON('foo'), $.getJSON('bar') ).done(function(foo, bar) { // foo & bar are jqXHR objects for the requests });
在其中一个Deferreds被拒绝的多个Deferreds案例中,jQuery.when立即激活其主Deferred的失败回调,即使某些Deferreds在此时仍未解决:
$.when( $.getJSON('foo'), $.getJSON('bar') ).fail(function(req) { // req is the jqXHR object for one of the failed requests });
当所有传递给jQuery的Deferreds都不再"未解决"时,我需要触发一个回调(即所有的"被解决"或"被拒绝").我可以使用200 OK代码发送JSON对象(而不是发送带有404 Not Found错误状态代码的JSON)并在done()方法中确定成功/错误,但我更喜欢保持我的API RESTful.我怎么能做到这一点?
我认为,要做到这一点最简单的方法就是保持辅助Deferred
对象周围的每个AJAX请求,并确保这一个总是解决:
var d1 = $.Deferred(); var d2 = $.Deferred(); var j1 = $.getJSON(...).complete(d1.resolve); var j2 = $.getJSON(...).complete(d2.resolve); $.when(j1, j2).done( only fires if j1 AND j2 are resolved ); $.when(d1, d2).done(function() { // will fire when j1 AND j2 are both resolved OR rejected // check j1.isResolved() and j2.isResolved() to find which failed });
这是利用额外的AJAX .complete()
方法,jQuery增加了对AJAX方法的承诺,这个方法被称为已解决和被拒绝的承诺.
NB:d1.resolve
它本身就是一个回调函数,它不需要包含在一个function() { ... }
块中.
@Alnitak的回答很聪明,帮助我抹去了我创造的一个黑客,我在某种程度上人为地解决了一个承诺 - 无论其根本结果如何 - 以便我可以使用'when'批处理多个请求并使用'done'无论成功/失败,都要继续.
我正在"回答"Alnitak的回答,希望能为他的建议提供另一种用途,支持任意数量的潜在承诺.
var asyncFunc, entity, entities, $deferred, $deferreds; // ... foreach (entity in entities) { $deferred = $.Deferred(); $deferreds.push($deferred); asyncFunc(entity).done(...).fail(...).always($deferred.resolve); } // ... $.when.apply($, $deferreds).done(...)
这是伪JavaScript,但它应该传达这种方法.对于一些任意大小的实体集,为每个实体创建一个延迟($ deferred)并将其推送到一个数组($ deferreds),进行异步调用,根据需要添加done/fail但总是包含一个解决这个问题的'always'实体的延期.注意 ''always'接收延迟的解析函数而不是它的调用.
'when'将$ deferreds数组转换为'when'的参数列表,并且由于这组延迟被保证解决(感谢始终),现在可以定义一个将被调用的'done'无论这些是成功还是失败,异步调用都会完成.
我最近制作了一个可能有用的插件.我叫它$.whenAll
.
此扩展将所有成功和失败视为进度事件.在所有承诺完成后,如果没有错误,全球承诺将得到解决.否则全球承诺将被拒绝.
$ .whenAll - https://gist.github.com/4341799(测试)
样品用法:
$.whenAll($.getJSON('foo'), $.getJSON('bar')) .then( doneCallback ,failcallback // progress callback // the only problem is $.ajax.done/fail states call their callbacks // with params in different locations (except for state) ,function(data, state, jqXhr) { if (state == 'success') { // do happy stuff } else { // error (fail) // `data` is actually the jqXhr object for failed requests // `jqXhr` is the text of the error "Not Found" in this example } } ) ;
我的实施:
插件代码:
jQuery.whenAll = function (deferreds) { var lastResolved = 0; var wrappedDeferreds = []; for (var i = 0; i < deferreds.length; i++) { wrappedDeferreds.push(jQuery.Deferred()); deferreds[i].always(function() { wrappedDeferreds[lastResolved++].resolve(arguments); }); } return jQuery.when.apply(jQuery, wrappedDeferreds).promise(); };
要使用它:
jQuery.whenAll([jQuery.get('/your-resource'), jQuery.get('/your-resource')]) .done( function(result1, result2) { console.log(result1[1]); console.log(result2[1]); });
看看小提琴: http ://jsfiddle.net/LeoJH/VMQ3F/