【问题标题】:How do I get the results of all failed call backs using $.when()如何使用 $.when() 获取所有失败回调的结果
【发布时间】:2016-12-01 17:06:03
【问题描述】:

假设我有一个延迟函数:

尝试 1:

$.when(validatePerson(123), validatePerson(456))
.done(function(data) { })
.fail(function(data1, data2) { });

尝试 2:

$.when(validatePerson(123), validatePerson(456))
.done(function(data) { })
.fail(function(data1) { }, 
      function(data2) { });

我想异步进行 2 次 AJAX 调用,但在失败时我希望能够确定第 1 次、第 2 次或两次调用中的哪一个失败,以便向用户显示适当的错误。

例如

  • 验证人 1 (id 123) 失败
  • 验证人 2 (id 456) 失败

但我似乎无法让它工作。 在尝试 1 中,data1 参数仅包含其中一个结果,而 data2 未定义。

在尝试 2 中,我使用相同的参数调用了两次函数回调。

【问题讨论】:

  • 这不能使用 JQuery 吗?这在 IE11 中是否有效,因为我也将 Promises 视为 ES6 的东西?

标签: jquery jquery-deferred


【解决方案1】:

$.when() 在您传递的第一个承诺被拒绝时终止。你不能用它得到所有被拒绝的承诺。您可以将它与其他代码一起使用来跟踪所有故障。

这是一个$.settle(),它等待您传递给它的所有承诺都被解决或拒绝,并返回一个 PromiseInspection 对象数组,您可以从中判断哪些已解决,哪些已被拒绝,以及它们的已解决值或被拒绝的原因是什么:

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

    // 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) {
                return wrapInPromise(errorVal);
            });
        }));
    }
})();

用法:

$.settle(arrayOfPromises).then(function(results) {
    // results is an array of PromiseInspection objects and you can
    // tell which are resolved and which are rejected
    results.forEach(function(item, index) {
         if (item.isFulfilled()) {
             console.log("promise #" + index + " is fulfilled with value: ", item.value(););
         } else {
             console.log("promise #" + index + " is rejected with reason: ", item.reason(););
         }
    });
});

【讨论】:

  • 谢谢,但对于 2 次 ajax 回调来说,这是很多代码!另外我想知道 fail() 函数中的回调数组的目的是什么?
  • @user183872 - $.when() 在第一个承诺失败后立即拒绝,因此您没有机会看到其他承诺发生了什么。它只是不那样工作。您可以将多个回调传递给.fail(),它只是同一事件的多个回调。它会一个接一个地调用它们,都具有相同的信息。
  • @user183872 - 您应该将其视为 jQuery 扩展的工具。您将它添加到您的项目中,以便您可以在任何时候使用$.settle(),以查看所有承诺的所有结果,而不管解决或拒绝。然后,您只需使用它来代替$.when(),这就是您想要的。这不是您每次想使用时都要输入的内容。
猜你喜欢
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 2015-08-16
  • 2022-01-20
  • 2018-12-07
  • 1970-01-01
  • 2018-01-31
相关资源
最近更新 更多