Abort Ajax requests using jQuery
使用jquery,如何取消/中止尚未收到响应的Ajax请求?
大多数jQueryAjax方法都返回一个xmlhttpRequest(或等效的)对象,因此您只需使用
请参阅文档:
- 中止方法(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,所以上面的代码仍然有效,尽管返回的对象不再是
更新3:
您不能撤回请求,但是您可以设置一个超时值,在此之后响应将被忽略。有关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演示
我们只需要解决这个问题并测试三种不同的方法。
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块之前将
没有可靠的方法可以做到这一点,而且一旦请求在进行中,我甚至不会尝试它;唯一合理反应的方法就是忽略响应。
在大多数情况下,它可能发生在这样的情况下:用户点击一个按钮太频繁,触发了许多连续的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); }); |
如果
然后可以在中止前设置
1 2 3 4 | // ↓ prevent page reload by abort() xhr.onreadystatechange = null; // ↓ may cause page reload xhr.abort(); |