题 使用jQuery中止Ajax请求


使用jQuery,我该怎么做 取消/中止Ajax请求 我还没有收到回复?


1637
2018-01-15 12:45


起源


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


答案:


大多数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,所以上面的代码仍然有效,尽管返回的对象不是 xhr 再也没有。见 3.0博客在这里

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


1597
2018-01-15 12:56



这就像点击浏览器上的“停止”按钮一样。它取消了请求。然后,您可以将同一个XHR对象重用于另一个请求。 - meouw
@brad不幸的是, abort 没有关闭与服务器建立的连接,所以 success 仍将被召唤。对于具有长轮询的Comet的实现,这是非常有问题的。 - pepkin88
@ErvWalter您可以发送另一个取消前一个请求的请求。 - Asad Saeeduddin
在我的测试中,请求在浏览器中止,但是.fail()方法是使用jqXHR,status = 0和jqXHR,statusMessage =“abort”调用的。 - BJ Safdie
它将不再适用于jQuery 3.0 blog.jquery.com/2016/01/14/jquery-3-0-beta-released - jcubic


您无法调用该请求,但可以设置超时值,之后将忽略响应。看到这个  用于jquery AJAX选项。我相信如果超过超时时间,将调用您的错误回调。每个AJAX请求都有一个默认超时。

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


106
2018-01-15 12:55





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

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

否则,只需忽略AJAX响应。


70
2018-01-15 12:56



在这种情况下,异步只是意味着请求不会中断脚本的流程。浏览器现在能够在请求完成之前提前中止请求。 - ElephantHunter
我们如何向服务器发送取消请求?我不明白服务器将如何知道停止处理的请求?你举个例子吗?谢谢。 - Lucky Soni
@LuckySoni,Elephanthunter只讨论客户端。服务器不受.abort请求的影响 - Kloar
@Kloar,如果服务器尚未收到请求(例如,大型多部分请求),客户端可能会关闭套接字,并且服务器将受到影响。 - white
PHP会自动检查已中止的请求,并自动终止。看到 php.net/manual/en/function.ignore-user-abort.php - hanshenrik


保存您在数组中进行的调用,然后在每个调用上调用xhr.abort()。

巨大的CAVEAT:您可以中止请求,但这只是客户端。服务器端仍然可以处理请求。如果您使用PHP或ASP等会话数据,会话数据将被锁定,直到ajax完成。因此,要允许用户继续浏览网站,您必须致电 session_write_close()。这将保存会话并将其解锁,以便等待继续的其他页面继续进行。没有这个,几个页面可以等待删除锁。


62
2018-03-28 11:34





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


45
2018-01-18 12:55





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

  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() - 方法,这可能会产生死锁情况。在我们的测试中,我们无法重现这种情况。


36
2018-03-06 14:29





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

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,则会好得多。


30
2017-10-15 09:14



我还检查一个请求是否已经运行,但我使用布尔值,因为它更轻。 - Zesty


meouw的解决方案 是正确的,但如果你对更多的控制感兴趣,那么你可以试试 Ajax Manager插件 对于jQuery。


19
2018-01-15 15:45



链接已经死了,Web Archive快照是301页...我发现一个看起来像是插件的分叉: github.com/aFarkas/Ajaxmanager/blob/master/... - brasofilo


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

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

//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 

11
2017-12-04 14:43





由于线程上的许多人都注意到,仅仅因为请求在客户端中止,服务器仍将处理请求。这会在服务器上产生不必要的负载,因为它正在做我们已经退出前端监听的工作。

我试图解决的问题(其他人可能会遇到的问题)是当用户在输入字段中输入信息时,我想要发出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);

});

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


10
2018-02-03 18:43