我正在寻找一种方法在两个ajax调用完成后进行回调:
$.when(
call1(),
call2()
).always(function() {
// Here I want to be sure the two calls are done and to get their responses
);
问题是其中一个调用可能会失败。所以,在我的代码中,总是会在不等待另一个调用的情况下调用它。
我如何等待两个完成的呼叫(成功或失败)?
答案 0 :(得分:11)
这是应该做的事情:
$.whenAllDone = function() {
var deferreds = [];
var result = $.Deferred();
$.each(arguments, function(i, current) {
var currentDeferred = $.Deferred();
current.then(function() {
currentDeferred.resolve(false, arguments);
}, function() {
currentDeferred.resolve(true, arguments);
});
deferreds.push(currentDeferred);
});
$.when.apply($, deferreds).then(function() {
var failures = [];
var successes = [];
$.each(arguments, function(i, args) {
// If we resolved with `true` as the first parameter
// we have a failure, a success otherwise
var target = args[0] ? failures : successes;
var data = args[1];
// Push either all arguments or the only one
target.push(data.length === 1 ? data[0] : args);
});
if(failures.length) {
return result.reject.apply(result, failures);
}
return result.resolve.apply(result, successes);
});
return result;
}
查看this Fiddle以查看其工作原理。
基本上它等待所有Deferreds无论是否失败都会完成并收集所有结果。如果我们有失败,返回的Deferred将失败并显示所有失败的列表,否则将解除所有成功。
答案 1 :(得分:1)
它并不漂亮,但是你可以为每个ajax调用设置一个全局的“completed”变量来完成设置。每个调用还会检查两个变量是否都已设置,如果是,则调用always函数。
答案 2 :(得分:0)
您还可以嵌套通话:
$.when(call1()).always(function(){
$.when(call2()).always(function(){
// Here I want to be sure the two calls are done and to get their responses
});
});
但当然这两个电话会彼此同步。
答案 3 :(得分:0)
达夫的回答很好。只有一个问题。当只有一个延迟时,事情就行不通了。
问题出在 jquery 的 when
方法中。
jquery.when: function( subordinate /* , ..., subordinateN */ ) { ...
它有这样一行:
// If resolveValues consist of only a single Deferred, just use that.
deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
这改变了参数的形状,所以我不得不把它放回我的代码期望的通用形状(即当多个延迟传递给 whenAllDone
时相同的形状)
const jqueryWhenUsesSubordinate = deferreds.length == 1;
const deferredArgs = jqueryWhenUsesSubordinate
? [[ arguments[ 0 ], arguments[ 1 ] ]]
: arguments
$.each(deferredArgs, function (i, resolvedArgs) {
var target = !resolvedArgs[0] ? failures : successes;
var data = resolvedArgs[1];
target.push(data.length === 1 ? data[0] : data);
});
此外,我更改了函数签名以更接近于 Promise.allSettled
,因为它应该采用延迟对象的数组参数,而不是循环遍历 arguments
来设置 {{1} } 数组,你遍历传入的参数。
这允许您以编程方式将可变长度的延迟创建到一个数组中,并将其传递给 deferreds
。