我搜索了许多非常相似的问题。我找到了一个几乎完全正在寻找的东西,除了它没有任何错误处理,并且在尝试实现错误处理时我遇到了一些问题。
我的目标是创建一个接收名称数组的函数,在循环中创建$ .ajax请求,将返回promise对象推送到一个数组中,然后我将其提供给$ .when.apply($,arrayOfPromises)。然后(//等解析一个延迟的主数据,其中arrayOfPromises中的所有promise都已被解析。最终结果是创建一个从ajax调用返回的数据数组。
到目前为止我有这个:http://jsfiddle.net/BGx2h/1/
这几乎就是我的需要。如果数组包含指向所有有效资源的指针,那么一切似乎都按预期工作。但是,如果有一个资源的调用不存在(例如我的小提琴中的/test/doesnt.exist.txt),那么“didnt.exist”的ajax调用在任何其他调用之前完成,即master延迟(connectiondfd)在其他调用有机会完成之前得到解决(您可能需要多次运行小提琴才能获得此结果)。这是我目前的功能:
function multiAsync() {
var i,data=[],connections=[],
targets=['John.Smith','Jane.Doe','Bob.Someone','doesnt.exist'];
var connectiondfd = $.Deferred();
for(i=0;i<targets.length;i++) {
connections.push($.ajax({
url:'http://porticium.ca/test/'+targets[i]+'.txt',
type:'GET',
async:true,
timeout:5000
}).then(function(newData) {
data.push(newData);
},function() {
data.push("NO DATA");
}));
}
$.when.apply($,connections)
.then(
function() { connectiondfd.resolve(); },
function() { connectiondfd.resolve(); }
);
$.when(connectiondfd).done(function() {
alert("FINAL: " + data);
});
}
肯定会欣赏这方面的一些帮助,它一直让我疯狂!
谢谢, 罗布
答案 0 :(得分:2)
所以我更多地玩这个并研究我接受的答案中提供的功能(再次感谢!)我设法找到另一个使用适合我目的的延迟解决方案。
我创建了一个名为whenAll的函数,它接受一个promises数组,创建一个延迟的master,并将完成和失败的回调添加到推送返回数据的每个promise,或者将错误消息添加到数组中然后检查长度数据数组与提供的promises数组的长度之间的关系,解析时它们是相同的。
这是:
function whenAll(promises) {
var i,data=[],dfd=$.Deferred();
for(i=0;i<promises.length;i++) {
promises[i].done(function(newData) {
data.push(newData);
if(data.length==promises.length) {
dfd.resolve(data);
}
}).fail(function() {
data.push("NO DATA");
if(data.length==promises.length) {
dfd.resolve(data);
}
});
}
return dfd.promise();
}
答案 1 :(得分:0)
如果你的一个promisses失败,$.Deferred.when
函数会立即触发,你可以创建一个'wrapper'延迟处理一系列promisses并在它们进来时调度它们然后激活master的自己的处理程序完成,即使有些失败,有些成功。这个特殊的功能只是从我拥有的通用工具文件中复制而来,为了简洁起见使用Underscore,但基本模式就是你所需要的:
function completed( firstParam ) {
var args = _.toArray( arguments ),
i = 0,
length = args.length,
pValues = new Array( length ),
count = length,
deferred = length <= 1 && firstParam && $.isFunction( firstParam.promise ) ? firstParam : $.Deferred(),
promise = deferred.promise(),
state = 'resolved';
function alwaysFunc( i ) {
return function ( value ) {
args[ i ] = arguments.length > 1 ? _.toArray( arguments ) : value;
state = ( this.state && this.state() === 'rejected' ) ? 'rejected' : state;
if ( !( --count ) ) deferred[ ( state === 'rejected' ? 'reject' : 'resolve' ) + 'With' ]( deferred, args );
};
}
function progressFunc( i ) {
return function ( value ) {
pValues[ i ] = arguments.length > 1 ? _.toArray( arguments ) : value;
deferred.notifyWith( promise, pValues );
};
}
if ( length > 1 ) {
for ( ; i < length; i++ ) {
if ( args[ i ] && args[ i ].promise && $.isFunction( args[ i ].promise ) )
args[ i ].promise().always( alwaysFunc( i ) ).progress( progressFunc( i ) );
else --count;
}
if ( !count ) deferred.resolveWith( deferred, args );
} else if ( deferred !== firstParam ) deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
return promise;
}
无论如何,您像往常一样创建并附加处理程序到各个请求/ promisses,然后通过apply
通过此函数传递它们。每个请求的状态都是单独处理的,并且该函数会跟踪仍有多少未解析的状态。一旦解决了所有问题,它就会根据集合触发自己的解决方案。即使一个或所有组件promisses失败,所有仍然执行,并且主延迟等待直到它们全部解决。在初始调用之后它不会处理添加进一步的promisses / deferreds - 创建你需要的所有,然后将它们传递给这个函数。
我不能赞同这个剧本:它是通过一个同事“传递给我” - 我认为是从其他地方获得的,但是世界上最差的人在代码中保留评论/归属。如果有人认出代码并且可以指向我的作者...