Skip to content Skip to sidebar Skip to footer

Strange/unexpected Jquery Promise Reject Behaviour

I am experimenting some strange behaviours with jQuery promises on reject. I have an array of promises, and I need to work with them when they all have been resolved/rejected. To d

Solution 1:

This is normal behavior for $.when(). If any promises you pass to $.when() reject, then $.when() will reject with the first reject reason that it finds. This is how it is coded.

This is similar to the way the ES6 Promise.all() works.

If you want all results, even if some promises reject, then you can use something like $.settle() or $.settleVal() that are defined in this code:

(function() {    

    functionisPromise(p) {
        return p && (typeof p === "object" || typeof p === "function") && typeof p.then === "function";
    }

    functionwrapInPromise(p) {
        if (!isPromise(p)) {
            p = $.Deferred().resolve(p);
        }
        return p;
    }

    functionPromiseInspection(fulfilled, val) {
        return {
            isFulfilled: function() {
                return fulfilled;
            }, isRejected: function() {
                return !fulfilled;
            }, isPending: function() {
                // PromiseInspection objects created here are never pendingreturnfalse;
            }, value: function() {
                if (!fulfilled) {
                    thrownewError("Can't call .value() on a promise that is not fulfilled");
                }
                return val;
            }, reason: function() {
                if (fulfilled) {
                    thrownewError("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 rejectedreturn p.then(function(val) {
                returnnewPromiseInspection(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 stepreturnwrapInPromise(newPromiseInspection(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 returnreturnArray.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) {
                returnwrapInPromise(errorVal);
            });
        }));
    }
})();

$.settle() always resolves and it resolves with an array of PromiseInspection objects that you can then iterate over to see which promises resolved and which rejected and what the value or reason was.

$.settleVal() is a little simpler to iterate, but a little less generic because it doesn't give you the reject reason. It always resolves with an array where a reject will have a default value that you pass to it in the array in place of the resolved value.

FYI, both $.settle() and $.settleVal() can both be passed an array of promises like $.settle(arrayOfPromises) or multiple promise arguments as $.settle(p1, p2, p3) (as $.when() works). This saves having to use .apply() when you have an array of promises.

Post a Comment for "Strange/unexpected Jquery Promise Reject Behaviour"