【问题标题】:Stopping JQuery promise with failure from propagating into wrapper停止 JQuery 承诺,但无法传播到包装器中
【发布时间】:2018-01-15 07:41:28
【问题描述】:

我的应用程序有一堆 $.ajax 调用,其中大部分具有 .done.fail 函数。

我想为 Ajax 调用编写一个包装器,这样如果一个函数没有 .fail 函数,或者如果 .fail 函数没有处理给定的错误(例如它只处理 404,但我得到一个 403),然后我希望包装器将其作为后备处理。

这是我写的:

function DoAjax(fn, errorText) {
    var deferred = $.Deferred();
    var result = fn();
    if (result === undefined)
        throw 'Function passed into DoAjax has not returned a promise.';
    result.always(function () {
        deferred.resolve(result);
    });
    result.fail(function () {
        alert('fail');
        deferred.fail();
    });
    return deferred.promise();
}

它主要按照我的意图工作,除了失败将执行两次 - 一次在方法 DoAjax 中,另一个在 Ajax 调用的位置。

我这样执行DoAjax

DoAjax(function () {
        var ajaxCall = $.ajax({
            method: "GET",
            url: baseUrl + "api/test"
        });

        ajaxCall.fail(function() { alert('failed the call'); });

        return ajaxCall;
});

我相信我可以通过手动创建一个 $.deferred 然后围绕它进行 $.ajax 调用来实现这一点,但我宁愿没有另一个包装器。

我正在使用 jQuery 2.2。

【问题讨论】:

  • 您使用的是什么版本的 jQuery?是 3+ 吗?
  • @charlietfl 2.2 如果需要可以升级

标签: javascript jquery ajax promise


【解决方案1】:

是时候进行一些核心学习了。需要注意几件事:

  1. .done().fail() 只是 jQuery.ajax() 选项,没有 .then(successCallback, errorCallback) 的所谓“过滤能力”(或 jQuery 3+ 中的 .then()/.catch())。换句话说,无论从 .done().fail() 回调返回的任何内容都不会对 jqxhr 承诺链产生下游影响。
  2. 在 jQuery
  3. 您的fn(),在这种情况下,返回jqxhr,而不是结果。因此,正如所写,if(result === undefined) 测试将始终返回false。 jqxhr 最终传递的结果不能这样测试。
  4. 如果您不确定函数是返回值还是 Promise,则将返回的值/对象包装在 jQuery.when(...) 中,例如 $.when(fn())
  5. 处理完 (3) 后,您可以直接从 jQuery.when(...) 返回的承诺链接。不需要明确的$.Deferred()

试试这个:

var baseUrl = '/';
function DoAjax(fn) {
    return $.when(fn()) // no need to test for fn() not returning a promise. `$.when(fn())` forces any non-Promise to Promise.
    .then(function(response) {
        console.log('success!', response);
    }).then(null, function(err) {
        console.error('B', err); // (LOG_2)
    });
}

DoAjax(function () {
    return $.ajax({
        method: "GET",
        url: baseUrl + "api/test"
    }).then(null, function(jqxhr, textStatus) {
        var err = new Error('Whoops! ' + jqxhr.status + ': ' + textStatus);
        console.error('A', err);

        // "throw behaviour"
        return err; // propagate the error (jQuery <3) or `throw err;` (jQuery 3+)

        // "catch behaviour"
        // return $.when('default response'); // "2" mutate failure into success (jQuery <3) or `return 'default response';` (jQuery 3+)
    });
});

Fiddle

现在尝试交换标记为“传播行为”和“捕获行为”的行,并观察日志中的差异。

如果您没有立即得到它,请不要担心。学习这些东西需要时间。

如果你有选择,那么使用 jQuery 3+,其中 jqxhr 和其他 Promises 比 jQuery Promise。

【讨论】:

  • 感谢您花时间写这篇文章。我没有使用您的确切解决方案(我最终将其抽象化),但它给了我需要做的事情。再次感谢,祝您有美好的一天。
  • 很高兴为您提供帮助。祝你好运。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-10
  • 2015-10-31
  • 1970-01-01
  • 2014-12-29
  • 1970-01-01
相关资源
最近更新 更多