javascript - 阻止 JQuery promise 传播到包装器失败

标签 javascript jquery ajax promise

我的应用程序有一堆 $.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。

最佳答案

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

  1. .done().fail() 只是 jQuery.ajax() 选项,没有所谓的“过滤能力” .then(successCallback, errorCallback)(或 jQuery 3+ 中的 .then()/.catch())。换句话说,无论从 .done().fail() 回调中返回什么,都不会对 jqxhr promise 链产生下游影响。
  2. 在 jQuery <3 中,errorCallback 不会自动捕获错误。默认行为是保留在 promise 链的错误路径上。为了给出 errorCallback 'catch' 行为,您必须从中返回已解决的 promise 。在 jQuery 3+ 中,默认情况下会捕获 errorCallback,但您可以返回被拒绝的 promise 或抛出以传播错误条件。
  3. 在这种情况下,您的 fn() 返回 jqxhr,而不是结果。因此,如所写,if(result === undefined) 测试将始终返回 false。 jqxhr最终下发的结果不能这样测试。
  4. 如果您不确定一个函数是返回一个值还是一个 Promise,那么将返回的值/对象包装在 jQuery.when(...) 中,例如 $.when(fn ()).
  5. 处理 (3) 后,您可以直接从 jQuery.when(...) 返回的 promise 链接。不需要显式的 $.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 和其他 Promise 比 jQuery <3.

关于javascript - 阻止 JQuery promise 传播到包装器失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48253972/

相关文章:

php - WordPress "admin-ajax.php"404 错误

ajax - 如何将 bool 结果发送到ajax调用

javascript - 未捕获的类型错误 : Cannot read property 'props' of undefined (reactjs) (very simpel)

javascript - 关于jQuery load函数的一些问题

javascript - 仅溢出 DIV 中的一个元素

javascript - Jquery Popup 不居中

javascript - 使用onkeyup时部分刷新做完全刷新

javascript - 使用仅获取一页的javascript在IFrame中打印PDF文件

javascript - 如果 ruby​​ on rails 中的 text_field 为空,如何禁用提交按钮?

javascript - 如何设置 TinyMCE 提及插件?