使用 jQuery 中止 Ajax 请求

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

答案

大多数 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 方法现在返回带有其他方法的 promise(例如 abort),因此上面的代码仍然有效,尽管返回的对象不再是xhr 。在此处查看3.0 博客

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

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

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

这是一个异步请求,这意味着一旦它被发送出去。

如果您的服务器由于 AJAX 请求而开始非常昂贵的操作,则您最好的办法是打开服务器以侦听取消请求,然后发送单独的 AJAX 请求以通知服务器停止其正在执行的操作。

否则,只需忽略 AJAX 响应。

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

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

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

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

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

最好总是这样做。

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,那就更好了。

只需致电 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);

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

就我而言,我使用的是这样的:

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

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

我试图解决的问题(其他人也可能会遇到)是,当用户在输入字段中输入信息时,我想触发对 Google 即搜即得类型的请求。

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

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 毫秒发送一个请求(您可以根据自己的需要自定义一个变量)。如果您在理解这里到底发生了什么时遇到麻烦, xhrCountxhrQueue到 if 块之前的控制台。