Mayday Mayday - 2 years ago 91
jQuery Question

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 do so, I am using this:

var array_res = [];

$.when.apply(null,array_res).always( function ( ) {
//Work to do
} );

function promiseResolve (c) {
var promise = $.Deferred();
return promise;

function promiseReject (c) {
var promise = $.Deferred();
return promise;

The issue is:

If I resolve both promises, everything works fine.

If I reject one of the promises, then the arguments come incomplete.

If I reject both of them, then the arguments come incomplete.

Here are 3 fiddles where you can check the behaviour:

What I need is a way to get the arguments for both, rejected and resolved.

Answer Source

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() {    

    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 =;

        return $.when.apply($, {
            // 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

    // 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 =, 1);
        return $.when.apply($, {
            p = wrapInPromise(p);
            return p.then(null, function(err) {
                return wrapInPromise(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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download