成功与.then之间的jQuery AJAX关系

时间:2019-02-22 23:25:53

标签: javascript jquery ajax

我正在尝试解决一个非常简单的问题,但我无法弄清楚。 我有以下代码:

<button onclick="run()">TEST</button>
<script>
    var counter = 0;
    function test() {           
        return $.ajax({
           url: "https://127.0.0.1:4432",
           success: function(html){
              console.log('success! test');
           },
           error: function() {
            if (counter++ < 3) {
                console.log("Retrying");
                $.ajax(this);
                return;
            }           
            console.log('ERROR! test');
           }
        });
    }   

    function run() {
        test()
        .then(
            function(){console.log('finished ALL OK')}, 
            function() {console.log('finished all ERROR')
        ;});

    }


</script>

我要实现的是,单击按钮后,AJAX请求将发送到服务器。如果AJAX失败,则将重试该请求。只有在所有重试完成后,才会调用“ .then”功能的成功或失败。

此刻,代码的行为就像AJAX调用被重试了三次一样,但是在第一次失败之后立即调用“ .then()”处理程序。

在浏览器的控制台中,它看起来像这样:

Console of the browser

所有重试后,我希望在最后看到“完成所有错误”文字。

希望这是有道理的,我将不胜感激。

4 个答案:

答案 0 :(得分:1)

success方法中的任何内容都不会影响同一jqXHR对象上的.then。对于您要寻找的链接,请考虑使用 .then.catch es代替:

function test() {
  let counter = 0;
  const get = () => $.ajax({ url: "https://127.0.0.1:4432" })
  .then((html) => {
    console.log('success');
  })
  .catch((err) => {
    if (counter++ < 3) {
      console.log("Retrying");
      return get();
    }
    console.log('ERROR! test');
    throw new Error();
  });
  return get();
}

test()
  .then(
  function() {
    console.log('finished ALL OK')
  },
  function() {
    console.log('finished all ERROR');
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

答案 1 :(得分:0)

function test(counter, $existingDeferred) {
        var $deferred = $existingDeferred || $.Deferred();
        
        $.ajax({
           url: "https://127.0.0.1:4432",
           success: function(html){
              console.log('success! test');
              $deferred.resolve(arguments);
           },
           error: function() {
            console.log('ERROR! test');
            
            if (counter < 3) {
                console.log("Retrying");
                test(++counter, $deferred);
            } else {
                $deferred.reject(arguments);
            }
          }
        });
        
        return $deferred;
    }   

    function run() {
        test(0)
        .then(
            function(){console.log('finished ALL OK')}, 
            function() {console.log('finished all ERROR')
        ;});

    }

您可以设置辅助延迟,以控制重试尝试的时间。

  • 传递计数器计数,并可以选择延迟第二计数
  • 如果我们没有现有的延期,请创建一个。
    • 执行ajax请求
    • 如果成功,则解决延迟的问题
    • 如果出错
    • 如果尝试没有成功,请递归计数器递归并递延现有方法
    • 否则,拒绝延期以表示流程结束
  • 返回将在成功后解决的延迟,或在所有尝试均被取消时拒绝的延迟。

答案 2 :(得分:0)

这是使用递归的另一种选择。

function test(fn, retries) {
  return fn().catch(error => 
    retries > 0 ? test(fn, retries - 1) : Promise.reject(error)
  );
}

test(() => $.ajax({ url: "https://127.0.0.1:4432" }), 3)
  .then(data => console.log('finished ALL OK'))
  .catch(lastError => console.log('finished all ERROR'));

如果以成功的响应调用了fn,则永远不会调用catch来停止递归。如果fn没有得到肯定的答复,它将检查是否还有重试。如果是这种情况,它将以较少的重试次数再次调用test,如果没有重试,则调用Promise.reject,以提供最后的错误。

注意:如果您未使用jQuery 3.0或更高版本,则必须将.catch(...)替换为.then(null, ...)

答案 3 :(得分:-1)

一种可能的解决方案是将整个操作包装在Promise中,尽管您可能需要使用polyfill来获得100%的浏览器支持。看起来像这样:

function test() {
    return new Promise(function(resolve, reject) {
        var counter = 0;
        $.ajax({
            url: "https://127.0.0.1:4432",
            success: function(html){
                console.log('success! test');
                resolve(html);
            },
            error: function() {
                if (counter++ < 3) {
                    console.log("Retrying");
                    $.ajax(this);
                }
                console.log('ERROR! test');
                reject('retries exceeded');
            }
        });
    });
}

function run() {
    test().then(
        function() { console.log('finished ALL OK'); },
        function() { console.log('finished all ERROR'); }
    );
}