使用 jQuery 中止 Ajax 请求

Abort Ajax requests using jQuery

提问人:lukewm 提问时间:1/15/2009 最后编辑:Always Helpinglukewm 更新时间:3/18/2022 访问量:705087

问:

是否有可能使用 jQuery,我取消/中止了我尚未收到响应的 Ajax 请求

JavaScript jQuery AJAX

评论

2赞 Luke Madhanga 9/13/2013
也许我误解了这个问题,但你不能简单地使用吗?$.ajaxStop
17赞 TheCarver 12/9/2013
@LukeMadhanga;我认为只有当所有 AJAX 请求都完成时才会检测到,它不会停止请求。根据我的经验,你会这样使用它:.使用是最好的选择。ajaxStop$(document).ajaxStop(function(){alert("All done")}).abort()

答:

123赞 tvanfosson 1/15/2009 #1

您无法调用请求,但可以设置一个超时值,超过该值后将忽略响应。有关 jquery AJAX 选项,请参阅此页面。我相信如果超过超时期限,将调用您的错误回调。每个 AJAX 请求都已存在默认超时。

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

78赞 Yuval Adam 1/15/2009 #2

这是一个异步请求,这意味着一旦发送,它就在那里。

如果您的服务器由于请求而启动了非常昂贵的操作,您能做的最好的事情就是打开服务器以侦听取消请求,并发送单独的请求,通知服务器停止它正在执行的任何操作。AJAXAJAX

否则,只需忽略响应即可。AJAX

评论

56赞 ElephantHunter 4/11/2012
在此上下文中,异步仅表示请求不会中断脚本的流。浏览器现在可以在请求完成之前提前中止请求。
1855赞 meouw 1/15/2009 #3

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

请参阅文档:

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,因此上面的代码仍然有效,尽管返回的对象不再是 a。请参阅此处的 3.0 博客xhr

更新 3:仍然适用于 jQuery 3.x。不要假设更新 2 是正确的。有关 jQuery Github 存储库的更多信息xhr.abort()

80赞 Tei 3/28/2012 #4

将您发出的呼叫保存在阵列中,然后对每个呼叫进行呼叫。xhr.abort()

需要注意的是:您可以中止请求,但这只是客户端。服务器端可能仍在处理请求。如果将 PHP 或 ASP 之类的东西用于会话数据,则会话数据将被锁定,直到 ajax 完成。因此,要允许用户继续浏览网站,您必须调用 session_write_close()。这将保存会话并解锁它,以便等待继续的其他页面将继续。如果没有这个,可能会有多个页面等待锁定被移除。

47赞 oyophant 3/6/2013 #5

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

  1. 按照@meouw的建议取消请求
  2. 执行所有请求,但只处理上次提交的结果
  3. 只要另一个请求仍处于待处理状态,就会阻止新请求

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();
  });
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="button" type="button" value="click" />

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

5赞 Marcus 7/25/2013 #6

我遇到了轮询问题,一旦页面关闭,轮询就会继续,所以在我的原因中,用户会错过更新,因为在页面关闭后的下一个 50 秒内设置了 mysql 值,即使我杀死了 ajax 请求,我想通了,使用 $_SESSION 来设置 var 不会在轮询中自行更新,直到它结束并且一个新的开始, 所以我所做的是在我的数据库中设置一个值为 0 = offpage ,当我轮询时,我查询该行并返回 false;当它为 0 时,因为在轮询中查询显然会获得当前值......

我希望这会有所帮助

12赞 Joe Nyambura 11/8/2013 #7

例如,只需使用 ajax.abort(),您就可以在发送另一个这样的请求之前中止任何待处理的 ajax 请求

//check for existing ajax request
if(ajax){ 
 ajax.abort();
 }
//then you make another ajax request
$.ajax(
 //your code here
  );
14赞 Billy 12/4/2013 #8

我正在做一个实时搜索解决方案,需要取消可能比最新/最新请求花费更长时间的待处理请求。

就我而言,我使用了这样的东西:

//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 
70赞 Salman A 1/18/2014 #9

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

  • 创建计数器
  • 启动 AJAX 请求时递增计数器
  • 使用计数器的当前值对请求进行“标记”
  • 在成功回调中,将标记与计数器进行比较,以检查它是否是最近的请求

代码粗略概述:

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 上的演示

16赞 brianrhea 2/4/2014 #10

正如线程上的许多人所指出的那样,仅仅因为请求在客户端中止,服务器仍将处理该请求。这会在服务器上造成不必要的负载,因为它正在执行我们在前端停止侦听的工作。

我试图解决的问题(其他人也可能会遇到)是,当用户在输入字段中输入信息时,我想发出一个请求,以获得 Google Instant 类型的感觉。

为了避免触发不必要的请求并保持前端的敏捷性,我做了以下工作:

var xhrQueue = [];
var xhrCount = 0;

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

    xhrQueue.push(xhrCount);

    setTimeout(function(){

        xhrCount = ++xhrCount;

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

    }, 150);

});

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

48赞 Tharindu Kumara 10/15/2014 #11

做这样的事情始终是最佳做法。

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 请求是否为 null,那就更好了。

评论

3赞 Zesty 7/29/2015
我还检查请求是否已经在运行,但我使用布尔值,因为它更轻。
1赞 Valerio Bozz 12/10/2021
' var $request;if ($request != null)' 为什么?这里的代码正在创建一个空变量,然后在没有任何严格检查的情况下检查它是否不为 null。这种无用的检查总是错误的教育意义是什么?此外,这是一个迟到的答案,只是告诉使用(上面已经回答过),但没有以任何方式解释。“做这样的事情总是最好的做法”这句话只是一个积极的流行语,它吸引没有经验的人投票。在澄清或改进之前,对此投了反对票。abort()
17赞 cuixiping 5/28/2015 #12

只需致电 xhr。abort() 无论是 jquery ajax 对象还是本机 XMLHTTPRequest 对象。

例:

//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);
10赞 comeGetSome 6/18/2015 #13

没有可靠的方法可以做到这一点,一旦请求在旅途中,我什至不会尝试;做出合理反应的唯一方法是忽略响应。

在大多数情况下,它可能发生在以下情况下:用户过于频繁地点击触发多个连续 XHR 的按钮,在这里您有很多选择,要么阻止按钮直到返回 XHR,要么在另一个运行时甚至不触发新的 XHR,提示用户向后倾斜 - 或者丢弃任何挂起的 XHR 响应,但最近的。

8赞 zloctb 1/4/2016 #14

以下代码演示如何启动和中止 Ajax 请求:

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();


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

评论

5赞 SnareChops 1/29/2016
请解释一下这如何解决这一问题。这将有助于OP和其他未来的搜索者。
5赞 ganesh 2/12/2016 #15

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

HTML全文:

<div id="info"></div>

JS代码:

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);   
});

评论

2赞 Bram Vanroy 7/7/2016
$.ajax 提供了一个选项,因此您无需编写自己的选项。只需使用 .timeout..., data: {...}, timeout: waitTime,...
6赞 vikyd 10/23/2016 #16

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

然后,您可以设置“中止前”以防止:onreadystatechange

// ↓ prevent page reload by abort()
xhr.onreadystatechange = null;
// ↓ may cause page reload
xhr.abort();
17赞 Soubhagya Kumar Barik 5/18/2018 #17

您可以使用以下命令中止任何连续的 ajax 调用

<input id="searchbox" name="searchbox" type="text" />

<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<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();
                    }
                }
            });
        });
</script>
1赞 Adrian P. 2/25/2021 #18

这是我基于上述许多答案的实现:

  var activeRequest = false; //global var
  var filters = {...};
  apply_filters(filters);

  //function triggering the ajax request
  function apply_filters(filters){
        //prepare data and other functionalities
        var data = {};
        //limit the ajax calls
        if (activeRequest === false){
          activeRequest = true;
        }else{
          //abort if another ajax call is pending
          $request.abort();
          //just to be sure the ajax didn't complete before and activeRequest it's already false
          activeRequest = true;        
        }

        $request = $.ajax({ 
          url : window.location.origin + '/your-url.php',
          data: data,
          type:'POST',
          beforeSend: function(){
            $('#ajax-loader-custom').show();
            $('#blur-on-loading').addClass('blur');
          },            
          success:function(data_filters){

              data_filters = $.parseJSON(data_filters);
              
              if( data_filters.posts ) {
                  $(document).find('#multiple-products ul.products li:last-child').after(data_filters.posts).fadeIn();
              }
              else{ 
                return;
              }
              $('#ajax-loader-custom').fadeOut();
          },
          complete: function() {
            activeRequest = false;
          }          
        }); 
  }