Jquery отложен - "всегда", вызванный при первом отказе
Я использую $.when
, чтобы связать некоторые объекты с отсрочкой, и если один из них терпит неудачу, метод always
будет вызван непосредственно после отказа, даже если у меня все еще есть некоторый отсрочка в состоянии ожидания.
var promises = [], defs = [];
for(var i=0 ; i < 10 ; i++){
defs.push($.Deferred());
promises.push(defs[i].promise());
}
var res = $.when.apply($, promises);
res.fail(function(){console.log('failed')});
res.done(function(){console.log('done')});
res.always(function(){console.log('always')});
res.then(function(){console.log('then, done')},
function(){console.log('then, failed')});
var j = 0;
var t = setInterval(function(){
if(j < 10){
if(j < 5) {
console.log('resolve');
defs[j++].resolve();
}
else {
console.log('reject');
defs[j++].reject();
}
}
else {
clearInterval(t);
}
}, 200);
Отметьте этот jsfiddle.
Возможно, это нормальное поведение. Но, в этом случае, как я могу поймать конец моей цепи, даже если некоторые из них потерпели неудачу?
Ответы
Ответ 1
Это по дизайну: метод разрешит своего хозяина Отложить, как только все Отложенные решения будут разрешены, или отклонить мастера Отложенное, как только один отложенных отклонений.
[...]
Обратите внимание, что некоторые из Отложенных могут оставаться неразрешенными в этой точке.
http://api.jquery.com/jQuery.when/
Вы можете сохранять ссылки на все отложенные записи и отслеживать их отдельно.
Что-то вроде этого:
var whenAll = function() {
var dfd = $.Deferred(),
len = arguments.length,
counter = 0,
state = "resolved",
resolveOrReject = function() {
if(this.state() === "rejected"){
state = "rejected";
}
counter++;
if(counter === len) {
dfd[state === "rejected"? "reject": "resolve"]();
}
};
$.each(arguments, function(idx, item) {
item.always(resolveOrReject);
});
return dfd.promise();
};
http://jsfiddle.net/cSy2K/2/
Ответ 2
Да, это нормальное поведение. Если кто-то терпит неудачу, то и то, что полагается на все, терпит неудачу. См. Также jQuery docs.
Итак, вам либо нужно отследить их вручную, либо вы только разрешили Promises в when
:
promises.push( defs[i].promise().then(function(x) {
return {result:x,resolved:true};
}, function(x) {
return (new $.Deferred).resolve({result:x,resolved:false});
})
);
При этом ваш res
будет вызывать только обратный вызов done
, когда обрабатываются все Promises, и он получит массив объектов, указывающий статус и результат их.