使用$ .when对jquery进行deffered ajax有一些缺点。成功处理ajax调用时非常棒。但如果一个失败,你就无法获得另一个请求的其他数据。
实施例
var ajax1Success = function() { return $.ajax(...); }; var ajax2Success = function() { return $.ajax(...); }; var ajax3BoundtoFail = function() { return $.ajax(...); }; $.when(ajax1Succes(), ajax2Success(), ajax3BoundtoFail()).done(function(a1, a2, a3) { // all good }).fail(function() { // not good... ajax3 is bound to fail });
如何从ajax请求获取其他数据成功的任何好方法?
答案 0 :(得分:1)
$.when()
快速失败"设计。这意味着失败的第一个承诺导致$.when()
拒绝,您只获得拒绝信息。来自jQuery doc:
该方法将尽快解决其主延迟 延迟解决,或拒绝主人延期一个 延期被拒绝
但是,您可以使用其他类型的功能来监控您的承诺组。这种类型的功能通常被称为"解决"等待所有承诺得到解决的地方,无论是否已经解决或拒绝,您都可以获得所有承诺的结果。
这里是我过去使用的jQuery promies的一个实现,你可以像这样使用:
$.settle([ajax1Succes(), ajax2Success(), ajax3BoundtoFail()]).then(function(results) {
// results is an array of PromiseInspection Objects
// for each of them, you can see if the corresponding promise
// succeeded with a value or failed with an error
results.forEach(function(pi, index) {
if (pi.isFulfilled()) {
console.log("Promise #" + (index + 1) + " succeeded with result " + pi.value());
} else {
console.log("Promise #" + (index + 1) + " failed with reason " + pi.reason());
}
});
});
或者,如果您不需要确切的错误,可以使用更简单的版本:
$.settleVal(null, [ajax1Succes(), ajax2Success(), ajax3BoundtoFail()]).then(function(results) {
// results contains the results from all the successful promises
// any promises that has an error will show null as the result
});
请注意,它们使用的界面更像标准Promise.all()
,它们采用一系列承诺并解析为一系列结果,因为这通常更容易在现实世界中使用。
而且,这是实施:
(function() {
function isPromise(p) {
return p && (typeof p === "object" || typeof p === "function") && typeof p.then === "function";
}
function wrapInPromise(p) {
if (!isPromise(p)) {
p = $.Deferred().resolve(p);
}
return p;
}
function PromiseInspection(fulfilled, val) {
return {
isFulfilled: function() {
return fulfilled;
}, isRejected: function() {
return !fulfilled;
}, isPending: function() {
// PromiseInspection objects created here are never pending
return false;
}, value: function() {
if (!fulfilled) {
throw new Error("Can't call .value() on a promise that is not fulfilled");
}
return val;
}, reason: function() {
if (fulfilled) {
throw new Error("Can't call .reason() on a promise that is fulfilled");
}
return val;
}
};
}
// pass either multiple promises as separate arguments or an array of promises
$.settle = function(p1) {
var args;
if (Array.isArray(p1)) {
args = p1;
} else {
args = Array.prototype.slice.call(arguments);
}
return $.when.apply($, args.map(function(p) {
// make sure p is a promise (it could be just a value)
p = wrapInPromise(p);
// Now we know for sure that p is a promise
// Make sure that the returned promise here is always resolved with a PromiseInspection object, never rejected
return p.then(function(val) {
return new PromiseInspection(true, val);
}, function(reason) {
// convert rejected promise into resolved promise by returning a resolved promised
// One could just return the promiseInspection object directly if jQuery was
// Promise spec compliant, but jQuery 1.x and 2.x are not so we have to take this extra step
return wrapInPromise(new PromiseInspection(false, reason));
});
})).then(function() {
// return an array of results which is just more convenient to work with
// than the separate arguments that $.when() would normally return
return Array.prototype.slice.call(arguments);
});
}
// simpler version that just converts any failed promises
// to a resolved value of what is passed in, so the caller can just skip
// any of those values in the returned values array
// Typically, the caller would pass in null or 0 or an empty object
$.settleVal = function(errorVal, p1) {
var args;
if (Array.isArray(p1)) {
args = p1;
} else {
args = Array.prototype.slice.call(arguments, 1);
}
return $.when.apply($, args.map(function(p) {
p = wrapInPromise(p);
return p.then(null, function(err) {
return wrapInPromise(errorVal);
});
}));
}
})();