jQuery - 延迟等待一组ajax请求完成甚至失败

时间:2012-08-28 04:02:37

标签: jquery-deferred deferred deferred-execution

如果一些ajax请求全部完成后如何执行函数,无论它们是成功还是错误输出?

我一直在尝试使用$.when.apply(this, array)传递一系列延迟的jqXHR对象。但就像文档说的那样

  

在多个Deferreds案例中,其中一个Deferreds被拒绝,jQuery.when立即>触发其主要Deferred的failCallbacks。请注意,此时某些延迟可能仍未解决。

如何利用jQuery延迟对象始终等待所有ajax调用完成?

也许我应该创建我自己的deferred,将包装所有其他延迟?如果是这样,我不太清楚如何设置它。

1 个答案:

答案 0 :(得分:0)

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

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

    // utility functions and objects
    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;
            }
        };
    }
})();

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

$.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/