jQuery $ .wait()for * all * deferred's被拒绝?

时间:2012-08-16 12:20:42

标签: jquery jquery-deferred

jQuery的Deferred API $.wait()有一个很好的功能,可用于处理多个Deferred s / Promise。它在以下时间返回:

  • Deferred的所有resolve() d

  • Deferred的一个已被reject()编辑

大部分时间这都是您想要的,但有时您想知道所有的时间是reject()

是否有一种简单或优雅的方法可以执行$.wait()之类的操作,但只有当所有Deferred被拒绝时才会这样做?

(可能还有其他用例,但我的目的是将其与waiting for the first of several Deferred's to resolve结合使用。)

2 个答案:

答案 0 :(得分:2)

本着Promise规范如何通过PromiseInspection对象展望未来的精神,这里有一个jQuery附加功能,可以告诉您所有承诺何时完成,无论是履行还是拒绝:

// 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);
    });
}

然后,您可以像这样使用它:

$.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
        }
    });
});

请记住,$.settle()将永远满足(永不拒绝),而实现的值是PromiseInspection个对象的数组,您可以查询每个对象以查看它是否已满足或被拒绝然后获取相应的价值或原因。有关示例用法,请参阅下面的演示:

工作演示:https://jsfiddle.net/jfriend00/y0gjs31r/

答案 1 :(得分:0)

我最近也遇到了同样的问题:我认为发生这种情况是因为$.when更像是Promise.all的实现。

我无法在jQuery文档和整个网络中找到Promise.allSettled替代项,因此,我尝试这样做:

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();
};

注意:我已经写了一个utils文件,所以对{{1}来说,唯一的 iterable 参数签名对我来说还可以}}精神(将Promise.allSettled作为单独的参数传递和获取),您将不得不多写一些...