我正在试验一些奇怪的行为与拒绝的jQuery承诺。 我有一系列的承诺,当他们全部被解决/拒绝时,我需要与他们合作。
为此,我正在使用它:
var array_res = [];
array_res.push(promiseResolve('a'));
array_res.push(promiseReject('b'));
$.when.apply(null,array_res).always( function ( ) {
console.log(arguments);
//Work to do
} );
function promiseResolve (c) {
var promise = $.Deferred();
promise.resolve({a:c});
return promise;
}
function promiseReject (c) {
var promise = $.Deferred();
promise.reject({b:c});
return promise;
}
问题是:
如果我同意这两个承诺,一切正常。
如果我拒绝其中一项承诺,那么争论就不完整了。
如果我拒绝他们两个,那么争论就不完整了。
以下是3个小提琴,您可以在其中查看行为:
https://jsfiddle.net/daepqzv1/1/
https://jsfiddle.net/daepqzv1/2/
https://jsfiddle.net/daepqzv1/3/
我需要的是获取两者的论据,拒绝和解决的方法。
答案 0 :(得分:2)
这是$.when()
的正常行为。如果您传递给$.when()
的任何承诺拒绝,则$.when()
将拒绝其找到的第一个拒绝原因。这是它的编码方式。
这类似于ES6 Promise.all()
的工作方式。
如果您想要所有结果,即使某些承诺拒绝,那么您可以使用此代码中定义的$.settle()
或$.settleVal()
之类的内容:
(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);
});
}));
}
})();
$.settle()
总是会解析并使用PromiseInspection
个对象进行解析,然后您可以迭代这些对象以查看哪些承诺已解决,哪些承诺被拒绝以及价值或原因是什么。
$.settleVal()
迭代起来有点简单,但有点不那么通用,因为它没有给你拒绝理由。它始终使用一个数组解析,其中拒绝将具有您在数组中传递给它的默认值,而不是已解析的值。
仅供参考,$.settle()
和$.settleVal()
都可以传递一个承诺数组$.settle(arrayOfPromises)
或多个承诺参数$.settle(p1, p2, p3)
(因为$.when()
有效) 。当你拥有一系列承诺时,这可以节省使用.apply()
。