jQuery $.wait() for *all* deferred's to be rejected?

前端 未结 2 1528
谎友^
谎友^ 2021-01-14 15:55

jQuery has a nice feature of its Deferred API, $.wait() for working with multiple Deferreds / Promises. It returns when:<

相关标签:
2条回答
  • 2021-01-14 16:22

    In the spirit of how the Promise specification is likely going for the future with a PromiseInspection object, here's a jQuery add-on function that tells you when all promises are done, whether fulfilled or rejected:

    // 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);
        }
    
        function PromiseInspection(fulfilled, val) {
            return {
                isFulfilled: function() {
                    return fulfilled;
                }, value: function() {
                    return fulfilled ? val: undefined;
                }, reason: function() {
                    return !fulfilled ? val: undefined;
                }
            };
        }
        return $.when.apply($, args.map(function(p) {
            // if incoming value, not a promise, then wrap it in a promise
            if (!p || (!(typeof p === "object" || typeof p === "function")) || typeof p.then !== "function") {
                p = $.Deferred().resolve(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
                // this is required in jQuery 1.x and 2.x (works in jQuery 3.x, but the extra .resolve() is not required in 3.x)
                return $.Deferred().resolve(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);
        });
    }
    

    Then, you can use it like this:

    $.settle(promiseArray).then(function(inspectionArray) {
        inspectionArray.forEach(function(pi) {
            if (pi.isFulfilled()) {
                // pi.value() is the value of the fulfilled promise
            } else {
                // pi.reason() is the reason for the rejection
            }
        });
    });
    

    Keep in mind that $.settle() will always fulfill (never reject) and the fulfilled value is an array of PromiseInspection objects and you can interrogate each one to see if it was fulfilled or rejected and then fetch the corresponding value or reason. See the demo below for example usage:

    Working demo: https://jsfiddle.net/jfriend00/y0gjs31r/

    0 讨论(0)
  • 2021-01-14 16:23

    i had the same problem lately: I think that occurs because $.when is more of a Promise.all implementation.

    I wasn't able to find a Promise.allSettled alternative in the jQuery documentation and across the web so here's my attempt to get it:

    const deferredsAllSettled = deferreds => {
        const settlements = [];
    
        deferreds.forEach(deferred => {
            const settlement = jQuery.Deferred();
    
            deferred.always(settlement.resolve);
    
            settlements.push(settlement);
        });
    
        const returnedDeferred = $.Deferred();
    
        jQuery.when
            .apply(jQuery, settlements)
            .then(() =>
                returnedDeferred.resolve(
                    deferreds.map(deferred => deferred.promise())
                )
            );
    
        return returnedDeferred.promise();
    };
    

    NOTE: I've written that for a utils file so the Promise.allSettled one-only iterable parameter signature was ok for me, if you want to write it in the $.when spirit (passing and getting the $.Deferreds as separate arguments) you'll have to write a little more...

    0 讨论(0)
提交回复
热议问题