关于javascript:使用jquery中止Ajax请求

Abort Ajax requests using jQuery

使用jquery,如何取消/中止尚未收到响应的Ajax请求?


大多数jQueryAjax方法都返回一个xmlhttpRequest(或等效的)对象,因此您只需使用abort()

请参阅文档:

  • 中止方法(msdn)。取消当前的HTTP请求。
  • 中止()(MDN)。如果请求已经发送,此方法将中止请求。
1
2
3
4
5
6
7
8
9
10
11
var xhr = $.ajax({
    type:"POST",
    url:"some.php",
    data:"name=John&location=Boston",
    success: function(msg){
       alert("Data Saved:" + msg );
    }
});

//kill the request
xhr.abort()

更新:从jquery 1.5开始,返回的对象是名为jqxhr的本机XMLHttpRequest对象的包装器。此对象似乎公开了所有本机属性和方法,因此上面的示例仍然有效。请参见jqxhr对象(jquery api文档)。

更新2:从jquery 3开始,ajax方法现在用额外的方法(比如abort)返回一个promise,所以上面的代码仍然有效,尽管返回的对象不再是xhr。在这里查看3.0博客。

更新3:xhr.abort()仍然在jquery 3.x上工作。不要假定更新2是正确的。有关jquery github存储库的详细信息。


您不能撤回请求,但是您可以设置一个超时值,在此之后响应将被忽略。有关jquery ajax选项,请参见本页。我相信如果超过超时时间,将调用您的错误回调。每个Ajax请求都已经有一个默认超时。

您也可以在请求对象上使用abort()方法,但是,虽然它会导致客户端停止侦听事件,但它may->strike>可能不会停止服务器处理它。


这是一个异步请求,意味着一旦发送,它就会出现在外面。

如果您的服务器由于Ajax请求而开始了一个非常昂贵的操作,那么您所能做的最好的事情就是打开服务器来监听取消请求,然后发送一个单独的Ajax请求,通知服务器停止它正在做的任何事情。

否则,只需忽略Ajax响应。


将您所做的调用保存在数组中,然后对每个调用xhr.abort()。

巨大的警告:您可以中止一个请求,但这只是客户端。服务器端可能仍在处理请求。如果在会话数据中使用诸如php或asp之类的东西,那么会话数据将被锁定,直到Ajax完成。因此,要允许用户继续浏览网站,您必须调用session_write_close()。这将保存会话并将其解锁,以便其他等待继续的页面继续。如果不这样做,可以有几个页面等待删除锁。


Ajax请求可能无法按启动顺序完成。您可以选择忽略除最新Ajax响应之外的所有Ajax响应,而不是中止:

  • 创建计数器
  • 在启动Ajax请求时增加计数器
  • 使用计数器的当前值"标记"请求
  • 在success回调中,将标记与计数器进行比较,以检查它是否是最近的请求

代码的大致轮廓:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var xhrCount = 0;
function sendXHR() {
    // sequence number for the current invocation of function
    var seqNumber = ++xhrCount;
    $.post("/echo/json/", { delay: Math.floor(Math.random() * 5) }, function() {
        // this works because of the way closures work
        if (seqNumber === xhrCount) {
            console.log("Process the response");
        } else {
            console.log("Ignore the response");
        }
    });
}
sendXHR();
sendXHR();
sendXHR();
// AJAX requests complete in any order but only the last
// one will trigger"Process the response" message

JSfiddle演示


我们只需要解决这个问题并测试三种不同的方法。

  • 是否按@meouw的建议取消请求?
  • 执行所有请求,但只处理上次提交的结果
  • 在另一个请求仍处于挂起状态时阻止新请求
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    var Ajax1 = {
      call: function() {
        if (typeof this.xhr !== 'undefined')
          this.xhr.abort();
        this.xhr = $.ajax({
          url: 'your/long/running/request/path',
          type: 'GET',
          success: function(data) {
            //process response
          }
        });
      }
    };
    var Ajax2 = {
      counter: 0,
      call: function() {
        var self = this,
          seq = ++this.counter;
        $.ajax({
          url: 'your/long/running/request/path',
          type: 'GET',
          success: function(data) {
            if (seq === self.counter) {
              //process response
            }
          }
        });
      }
    };
    var Ajax3 = {
      active: false,
      call: function() {
        if (this.active === false) {
          this.active = true;
          var self = this;
          $.ajax({
            url: 'your/long/running/request/path',
            type: 'GET',
            success: function(data) {
              //process response
            },
            complete: function() {
              self.active = false;
            }
          });
        }
      }
    };
    $(function() {
      $('#button').click(function(e) {
        Ajax3.call();
      });
    })
    1
    2
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
    <input id="button" type="button" value="click" />

    在我们的案例中,我们决定使用方法3,因为它可以减少服务器的负载。但我不能100%确定jquery是否保证调用.complete()-方法,这可能会导致死锁情况。在我们的测试中,我们无法重现这种情况。


    做这样的事情总是最好的做法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var $request;
    if ($request != null){
        $request.abort();
        $request = null;
    }

    $request = $.ajax({
        type :"POST", //TODO: Must be changed to POST
        url :"yourfile.php",
        data :"data"
        }).done(function(msg) {
            alert(msg);
        });

    但是,如果检查if语句以检查Ajax请求是否为空,则会更好。


    Meouw的解决方案是正确的,但是如果您对更多的控制感兴趣,那么可以尝试jquery的Ajax管理器插件。


    我正在执行实时搜索解决方案,需要取消可能比最新/最新请求花费更长时间的挂起请求。

    在我的案例中,我使用了类似的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //On document ready
    var ajax_inprocess = false;

    $(document).ajaxStart(function() {
    ajax_inprocess = true;
    });

    $(document).ajaxStop(function() {
    ajax_inprocess = false;
    });

    //Snippet from live search function
    if (ajax_inprocess == true)
    {
        request.abort();
    }
    //Call for new request

    只需调用xhr.abort(),无论是jquery ajax对象还是本机xmlhttpRequest对象。

    例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //jQuery ajax
    $(document).ready(function(){
        var xhr = $.get('/server');
        setTimeout(function(){xhr.abort();}, 2000);
    });

    //native XMLHTTPRequest
    var xhr = new XMLHttpRequest();
    xhr.open('GET','/server',true);
    xhr.send();
    setTimeout(function(){xhr.abort();}, 2000);

    正如线程上的许多人所指出的,仅仅因为请求在客户端被中止,服务器仍将处理该请求。这会在服务器上产生不必要的负载,因为它正在做我们已经停止在前端监听的工作。

    我试图解决的问题是,当用户在输入字段中输入信息时,我想启动一个对Google即时感觉类型的请求。

    为了避免发出不必要的请求并保持前端的敏捷性,我执行了以下操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    var xhrQueue = [];
    var xhrCount = 0;

    $('#search_q').keyup(function(){

        xhrQueue.push(xhrCount);

        setTimeout(function(){

            xhrCount = ++xhrCount;

            if (xhrCount === xhrQueue.length) {
                // Fire Your XHR //
            }

        }, 150);

    });

    这基本上每150ms发送一个请求(一个您可以根据自己的需要定制的变量)。如果您无法理解这里到底发生了什么,请在if块之前将xhrCountxhrQueue登录到控制台。


    没有可靠的方法可以做到这一点,而且一旦请求在进行中,我甚至不会尝试它;唯一合理反应的方法就是忽略响应。

    在大多数情况下,它可能发生在这样的情况下:用户点击一个按钮太频繁,触发了许多连续的xhr,这里有许多选项,要么在返回xhr之前阻止该按钮,要么甚至在另一个运行时不触发新的xhr,提示用户向后倾斜,或者丢弃任何未决的xhr响应,但最近的。


    只需使用ajax.abort()例如,在发送另一个类似这样的请求之前,您可以中止任何挂起的ajax请求。

    1
    2
    3
    4
    5
    6
    7
    8
    //check for existing ajax request
    if(ajax){
     ajax.abort();
     }
    //then you make another ajax request
    $.ajax(
     //your code here
      );

    您可以使用此命令中止任何连续的Ajax调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <input id="searchbox" name="searchbox" type="text" />

    <script src="http://code.jquery.com/jquery-1.11.0.min.js">

    <script type="text/javascript">
         var request = null;
            $('#searchbox').keyup(function () {
                var id = $(this).val();
                request = $.ajax({
                    type:"POST", //TODO: Must be changed to POST
                    url:"index.php",
                    data: {'id':id},
                    success: function () {

                    },
                    beforeSend: function () {
                        if (request !== null) {
                            request.abort();
                        }
                    }
                });
            });

    以下代码显示启动和中止Ajax请求:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    function libAjax(){
      var req;
      function start(){

      req =    $.ajax({
                  url: '1.php',
                  success: function(data){
                    console.log(data)
                  }
                });

      }

      function stop(){
        req.abort();
      }

      return {start:start,stop:stop}
    }

    var obj = libAjax();

     $(".go").click(function(){


      obj.start();


     })



     $(".stop").click(function(){

      obj.stop();


     })
    1
    2
    3
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
    <input type="button" class="go" value="GO!">
       <input type="button" class="stop" value="STOP!">


    我遇到了轮询问题,当页面关闭后,轮询继续进行,因此在我的原因中,用户可能会错过一个更新,因为在页面关闭后的50秒内,MySQL值被设置为一个值,即使我取消了Ajax请求,我还是想了一下,使用$u会话设置var在轮询中不会更新它的自身,直到它结束,一个新的e已经开始了,所以我在数据库中设置了一个值0=offsage,当我进行轮询时,我查询该行并返回false;当它为0时,作为轮询中的查询,显然会得到当前的值…

    我希望这有帮助


    我共享了一个演示,演示了如何取消Ajax请求——如果在预定义的等待时间内没有从服务器返回数据。

    HTML:

    1
     

    JS代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    var isDataReceived= false, waitTime= 1000;
    $(function() {
        // Ajax request sent.
         var xhr= $.ajax({
          url: 'http://api.joind.in/v2.1/talks/10889',
          data: {
             format: 'json'
          },    
          dataType: 'jsonp',
          success: function(data) {      
            isDataReceived= true;
            $('#info').text(data.talks[0].talk_title);        
          },
          type: 'GET'
       });
       // Cancel ajax request if data is not loaded within 1sec.
       setTimeout(function(){
         if(!isDataReceived)
         xhr.abort();    
       },waitTime);  
    });


    如果xhr.abort();导致页面重新加载,

    然后可以在中止前设置onreadystatechange,以防止:

    1
    2
    3
    4
    // ↓ prevent page reload by abort()
    xhr.onreadystatechange = null;
    // ↓ may cause page reload
    xhr.abort();