4

我需要创建一个函数,在给定限制之前重试失败的 ajax 请求,我需要确保仅在超过最大重试次数时才拒绝承诺,如下所示:

function my_ajax(...) { ... }

// then I use it this way
return $.when(my_ajax('foo.json'), my_ajax('bar.json'))

为了与 jQuery.when 一起工作,应该只返回一个 Promise,my_ajax它应该在内部 jQuery.ajax 被解析时被解析,并且只有在重试次数达到最大值时才会被拒绝。

我制作的代码是这样的:

function do_ajax(args, dfd, attempt) {
    dfd     || (dfd = $.Deferred());
    attempt || (attempt = 1);

    $.ajax(args).then(dfd.resolve, function(xhr, text_status, error_thrown) {
        console.error(/* something useful */);
        attempt++;

        if(attempt > 3) {
            dfd.reject(xhr, text_status, error_thrown);
        } else {
            do_ajax(args, dfd, attempt);
        }
    });

    return dfd.promise();
}

// in some random code
return $.when(do_ajax({url:'foo.json'}), do_ajax({url:'bar.json'});

这对我有用*,但有点难以理解。问题是:有没有更好(更容易阅读)的方法来做到这一点?

* - 实际上我有时并没有测试失败,但是当第一个 ajax 请求成功时我工作正常。

4

2 回答 2

4

我认为您的代码是正确的方法,将您的调用包装在一个新的 Deferred 中并返回它,直到达到所有尝试。

您可以尝试将递归调用包含在匿名函数中以提高可读性。

我是这样写的:

function doAjax(ajaxArgs, attempt) {
    // the wrapped returned dfd
    var wrappedDfd = $.Deferred();

    // your nested call using attempt counter
    (function nestedCall() {
        // if call succed, resolve the wrapped dfd
        $.ajax(ajaxArgs).then(wrappedDfd.resolve, function() {
            // update attempt counter
            attempt--;
            if (attempt > 0) {
                // try another call
                nestedCall();
            } else {
                // max try reached, reject wrapped dfd
                wrappedDfd.reject();
            }
        });
    })();

    return wrappedDfd.promise();
};

这与您的代码非常相似。

这是jsfiddle。出于测试目的,我用模拟工厂调用替换了 doAjax 参数,但代码保持不变。

希望这有帮助。

于 2013-07-12T08:44:28.020 回答
2

基于Mordhak的回答和 SO dherman周围的其他一些人创建了一个 jQuery 插件:jquery.ajaxRetry ( GitHub repo ),johnkpaul 也是如此 jquery.ajax -retry

jquery.ajax重试

例子

$.ajax({
  // Retry this request up to 2 times
  shouldRetry: 2
});
  • 可以无限期重试
  • 可以重试n次数
  • 可以运行一个函数并评估 totruefalseinshouldRetry以确定它是否应该继续重试

jquery.ajax-重试

例子

$.ajax(options).retry({times:3, timeout:3000}).then(function(){
    alert("success!");
  }); 
  • 可以重试n次数
  • 可以指定重试之间的等待时间
  • 可以指定要重试的状态码
于 2013-11-11T18:46:45.533 回答