停止传播到包装器

时间:2018-01-14 20:43:42

标签: 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 个答案:

答案 0 :(得分:2)

现在是时候进行一些核心学习了。需要采取一些措施:

  1. .done().fail()只是jQuery.ajax()选项,没有所谓的过滤功能" jQuery 3+中的.then(successCallback, errorCallback)(或.then() / .catch())。换句话说,从.done().fail()回调返回的任何内容都不会对jqxhr承诺链产生下游影响。
  2. 在jQuery< 3中,errorCallback不会自动捕获错误。默认行为是保留在promise链的错误路径上。为了给出一个错误回调,赶上'行为,那么你必须从它返回一个已解决的承诺。在jQuery 3+中,默认情况下会捕获errorCallback,但您可以返回被拒绝的promise或throw来传播错误条件。
  3. 在这种情况下,您的fn()会返回jqxhr,而非结果。因此,如上所述,if(result === undefined)测试将始终返回false。 jqxhr最终提供的结果无法以这种方式进行测试。
  4. 如果您不确定函数是返回值还是Promise,请将返回的值/对象包装在jQuery.when(...)中,例如$.when(fn())
  5. 通过(3)处理,您可以直接链接jQuery.when(...)返回的承诺。没有明确的$.Deferred()
  6. 试试这个:

    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

    现在尝试更换标记为&#34的行;传播行为&#34;并且&#34;捕捉行为&#34;并观察日志中的差异。

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

    如果您有选择,那么就开始使用jQuery 3+,其中jqxhr和其他Promise更接近javascript的原生Promise而不是jQuery&lt; 3。