Javascript jQuery.when-当所有延迟不再';未解决';(已解决或拒绝)?
当多个延迟对象被传递到时,该方法从一个新的“主”延迟对象返回承诺,该对象跟踪已传递的所有延迟的聚合状态 该方法将Javascript jQuery.when-当所有延迟不再';未解决';(已解决或拒绝)?,javascript,jquery,rest,jquery-deferred,Javascript,Jquery,Rest,Jquery Deferred,当多个延迟对象被传递到时,该方法从一个新的“主”延迟对象返回承诺,该对象跟踪已传递的所有延迟的聚合状态 该方法将 在所有延迟解决后尽快解决其主延迟,或 一旦其中一个延期被拒绝,立即拒绝延期的主控 如果主延迟已解析(即所有延迟已解析),则会将传递给jQuery.when的所有延迟的解析值传递给它。例如,当延迟是jQuery.ajax()请求时,参数将是请求的jqXHR对象,其顺序与参数列表中给出的顺序相同: $.when( $.getJSON('foo'), $.getJSON('bar') ).
$.when( $.getJSON('foo'), $.getJSON('bar') ).done(function(foo, bar) {
// foo & bar are jqXHR objects for the requests
});
在多次延迟的情况下,其中一个延迟被拒绝,jQuery.when会立即为其主延迟发出失败回调,即使此时某些延迟可能仍未解决:
$.when( $.getJSON('foo'), $.getJSON('bar') ).fail(function(req) {
// req is the jqXHR object for one of the failed requests
});
当所有延迟传递给jQuery.when不再“未解决”(即所有延迟都是“已解决”或“已拒绝”)时,我需要启动回调。我可以发送带有200个OK代码的JSON对象(而不是发送带有404个Not Found错误状态代码的JSON),并在done()方法中确定成功/错误,但我更喜欢保持API RESTful。如何实现这一点?我认为最简单的方法是为每个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方法的承诺中,该方法用于已解决的承诺和已拒绝的承诺
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(...)
注意:d1.resolve本身就是一个回调函数,它不需要包装在函数(){…}
block.@Alnitak answer很聪明,它帮助我清除了我创建的一个黑客程序,在这个程序中,我在某种程度上人为地解决了一个承诺——不管潜在的结果如何——以便我可以使用“when”批量处理多个请求,并使用“done”继续处理,不管它们成功/失败
我“回答”阿尔尼塔克的回答是希望为他的建议提供另一个用途,该建议支持任意数量的潜在承诺
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($deferred),并将其推送到一个数组($deferreds),进行异步调用,根据需要添加done/fail,但始终包含一个“always”,用于解析该实体的$deferred。注意,“始终”接收延迟的解析函数,而不是其调用
“when”将$deferreds数组转换为“when”和的参数列表,因为这组延迟保证可以解决(多亏了always),现在可以定义一个“done”,在所有异步调用完成后将调用它,而不管这些调用是否成功。这里是一个jQuery插件,我修改了$的实际核心代码。when()
来使用您的语义。由于缺少更好的名称,它被称为$.myWhen()
:
(函数($){
$.myWhen=函数(从属/*,…,从属*/){
var i=0,
responseValues=Array.prototype.slice.call(参数),
长度=响应值。长度,
//未完成的下属数量
剩余=长度!==1 | |(substance&&jQuery.isFunction(substance.promise))?长度:0,
//主延迟。如果responseValue只包含一个延迟值,就使用它。
递延=剩余===1?下级:jQuery.deferred(),
//更新所有“解决”、“拒绝”和“进度”值的函数
updateFunc=函数(i、上下文、值){
返回函数(值){
上下文[i]=这个;
values[i]=arguments.length>1?Array.prototype.slice.call(arguments):值;
如果(值===progressValues){
deferred.notifyWith(上下文、值);
}否则如果(!(-剩余)){
延迟。解析(上下文、值);
}
};
},
进度价值观、进度上下文、响应文本;
//将听众添加到延迟的下属;将其他人视为已解决
如果(长度>1){
progressValues=新数组(长度);
ProgressContext=新数组(长度);
responseContext=新数组(长度);
对于(;i
只需将此代码放在加载jQuery的位置之后,$.myWhen()
函数将与$.when()
一起提供。除了语义之外,其他一切都是100%完全相同的。我最近制作了一个插件,可能会有所帮助。我叫它$。当所有的
此扩展将所有成功和失败视为进度事件。
在所有承诺完成后,全球承诺得到解决
如果没有错误。否则,全球承诺将被拒绝
$.whenAll-()
示例用法:
$.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]);
});
查看小提琴:
对Leo Hernandez解决方案的改进,用于更一般的用例,而不仅仅是从服务器获取资源,例如可以在
$.whenAll = function (deferreds) {
var lastResolved = 0;
var wrappedDeferreds = [];
for (var i = 0; i < deferreds.length; i++) {
wrappedDeferreds.push($.Deferred());
if (deferreds[i] && deferreds[i].always) {
deferreds[i].always(wrappedDeferreds[lastResolved++].resolve);
} else {
wrappedDeferreds[lastResolved++].resolve(deferreds[i]);
}
}
return $.when.apply($, wrappedDeferreds).promise();
};
$.whenAll([1, $.Deferred().resolve("Good"), $.Deferred().reject("Bad")])
.done(function (result1, result2, result3) {
// result1 -> 1
// result2 -> "Good"
// result3 -> "Bad"
});
var entities;
// ...
var deferreds = entities.map(function() {
var deferred = $.Deferred();
asyncFunc(this).done(...).fail(...).always(deferred.resolve);
return deferred;
}
// ...
$.when.apply($, deferreds).done(...)
$.when
(
$.getJSON(...).then(function (results)
{
console.log('SUCCESS REQUEST 1 BY ITSELF', results);
}),
$.getJSON(...).then(function (results)
{
console.log('SUCCESS REQUEST 2 BY ITSELF', results);
})
).then
(
function (results1, results2)
{
console.log('BOTH REQUESTS SUCCESSFUL...');
console.log('results1', results1);
console.log('results2', results2);
},
function (error1, error2)
{
console.log('AT LEAST 1 REQUEST FAILED...');
console.log('error1', error1);
console.log('error2', error2);
}
);