Hủy bỏ các yêu cầu Ajax bằng jQuery


1827

Sử dụng jQuery, làm cách nào tôi có thể hủy / hủy yêu cầu Ajax mà tôi chưa nhận được phản hồi từ đó?


2
Có lẽ tôi đã hiểu nhầm câu hỏi, nhưng bạn không thể đơn giản sử dụng $.ajaxStop?
Luke Madhanga

17
@LukeMadhanga; Tôi nghĩ rằng ajaxStopchỉ phát hiện khi tất cả các yêu cầu AJAX hoàn thành, nó không dừng yêu cầu. Theo kinh nghiệm của tôi, bạn sẽ sử dụng nó như thế này : $(document).ajaxStop(function(){alert("All done")}). Sử dụng .abort()là lựa chọn tốt nhất.
TheCarver

Câu trả lời:


1744

Hầu hết các phương thức Ajax của jQuery trả về một đối tượng XMLHttpRequest (hoặc tương đương), vì vậy bạn chỉ có thể sử dụng abort().

Xem tài liệu:

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

CẬP NHẬT: Kể từ jQuery 1.5, đối tượng được trả về là một trình bao bọc cho đối tượng XMLHttpRequest gốc được gọi là jqXHR. Đối tượng này dường như để lộ tất cả các thuộc tính và phương thức riêng nên ví dụ trên vẫn hoạt động. Xem Đối tượng jqXHR (tài liệu API jQuery).

CẬP NHẬT 2: Kể từ jQuery 3, phương thức ajax hiện trả lại một lời hứa với các phương thức bổ sung (như hủy bỏ), do đó đoạn mã trên vẫn hoạt động, mặc dù đối tượng được trả về không xhrcòn nữa. Xem blog 3.0 tại đây .

CẬP NHẬT 3 : xhr.abort()vẫn hoạt động trên jQuery 3.x. Đừng cho rằng bản cập nhật 2 là chính xác. Thông tin thêm về kho lưu trữ jQuery Github .


12
Giống như nhấp vào nút 'dừng' trên trình duyệt của bạn. Nó hủy bỏ yêu cầu. Sau đó, bạn có thể sử dụng lại cùng một đối tượng XHR cho một yêu cầu khác.
meouw

65
@brad Thật không may, abortkhông đóng kết nối được thiết lập với máy chủ, vì vậy successsẽ vẫn được gọi. Điều này rất có vấn đề đối với việc triển khai Sao chổi với việc bỏ phiếu dài.
pepkin88

6
@ErvWalter Bạn có thể gửi một yêu cầu khác hủy bỏ yêu cầu trước đó.
Asad Saeeduddin

8
Trong các thử nghiệm của tôi, yêu cầu bị hủy bỏ trên trình duyệt, nhưng phương thức .fail () được gọi với jqXHR, status = 0 và jqXHR, statusMessage = "hủy bỏ"
BJ Safdie

9
.abort()vẫn hoạt động với tôi trong jQuery 3.2.1. Nhận xét này trong một vấn đề github có liên quan của một thành viên nhóm cốt lõi jQuery dường như ngụ ý rằng câu trả lời này không chính xác và .abort() không bị xóa.
alarive

117

Bạn không thể nhớ lại yêu cầu nhưng bạn có thể đặt giá trị hết thời gian chờ mà sau đó phản hồi sẽ bị bỏ qua. Xem trang này để biết các tùy chọn AJAX jquery. Tôi tin rằng cuộc gọi lại lỗi của bạn sẽ được gọi nếu vượt quá thời gian chờ. Đã có thời gian chờ mặc định cho mọi yêu cầu AJAX.

Bạn cũng có thể sử dụng phương thức hủy bỏ () trên đối tượng yêu cầu, nhưng, trong khi nó sẽ khiến máy khách ngừng lắng nghe sự kiện, nó thể sẽ không ngăn máy chủ xử lý nó.


74

Đó là một sự không đồng bộ yêu cầu , nghĩa là một khi nó được gửi ra ngoài đó.

Trong trường hợp máy chủ của bạn đang bắt đầu một hoạt động rất tốn kém do yêu cầu AJAX, cách tốt nhất bạn có thể làm là mở máy chủ của mình để lắng nghe yêu cầu hủy và gửi một yêu cầu AJAX riêng để thông báo cho máy chủ dừng mọi hoạt động.

Nếu không, chỉ cần bỏ qua phản hồi AJAX.


48
Trong ngữ cảnh này, không đồng bộ đơn giản có nghĩa là yêu cầu không làm gián đoạn dòng chảy của tập lệnh. Trình duyệt hiện có khả năng hủy bỏ yêu cầu sớm trước khi yêu cầu được hoàn thành.
ElephantHunter

4
Làm thế nào chúng ta có thể gửi yêu cầu hủy đến máy chủ? Tôi không hiểu làm thế nào máy chủ sẽ biết yêu cầu ngừng xử lý? Bạn có thể cho một ví dụ? Cảm ơn bạn.
Lucky Soni

3
@LuckySoni, Elephanthunter chỉ thảo luận về phía khách hàng. Máy chủ sẽ không bị ảnh hưởng bởi yêu cầu .abort
Kloar

4
@Kloar, nếu máy chủ chưa nhận được yêu cầu (ví dụ: yêu cầu nhiều phần lớn), máy khách có thể đóng ổ cắm và máy chủ sẽ bị ảnh hưởng.
trắng

4
PHP tự động kiểm tra các yêu cầu bị hủy bỏ và cũng tự động chấm dứt. thấy php.net/manual/en/function.ignore-user-abort.php
hanshenrik

68

Lưu các cuộc gọi bạn thực hiện trong một mảng, sau đó gọi xhr.abort () trên mỗi mảng.

CAGEAT HUGE: Bạn có thể hủy bỏ yêu cầu, nhưng đó chỉ là phía khách hàng. Phía máy chủ vẫn có thể xử lý yêu cầu. Nếu bạn đang sử dụng một cái gì đó như PHP hoặc ASP với dữ liệu phiên, dữ liệu phiên sẽ bị khóa cho đến khi ajax kết thúc. Vì vậy, để cho phép người dùng tiếp tục duyệt trang web, bạn phải gọi session_write_close (). Điều này sẽ lưu phiên và mở khóa để các trang khác đang chờ tiếp tục sẽ tiếp tục. Nếu không có điều này, một vài trang có thể chờ khóa được gỡ bỏ.


vì bạn luôn hủy bỏ cái trước đó, bạn có thể luôn luôn làm điều đó không? (và không cần sử dụng một mảng)
phân cực

60

Yêu cầu AJAX có thể không hoàn thành theo thứ tự chúng đã được bắt đầu. Thay vì hủy bỏ, bạn có thể chọn bỏ qua tất cả các phản hồi AJAX ngoại trừ phản hồi gần đây nhất:

  • Tạo một quầy
  • Tăng bộ đếm khi bạn bắt đầu yêu cầu AJAX
  • Sử dụng giá trị hiện tại của bộ đếm để "đóng dấu" yêu cầu
  • Trong cuộc gọi lại thành công, so sánh tem với bộ đếm để kiểm tra xem đó có phải là yêu cầu gần đây nhất không

Phác thảo thô của mã:

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

Bản demo trên jsFiddle


Do cần phải hủy yêu cầu XHR (xem các bình luận khác trên trang này), đây có lẽ là tùy chọn tốt nhất và đơn giản nhất.
Quinn Comendant

41

Chúng tôi chỉ phải giải quyết vấn đề này và thử nghiệm ba cách tiếp cận khác nhau.

  1. không hủy yêu cầu theo đề xuất của @meouw
  2. thực hiện tất cả các yêu cầu nhưng chỉ xử lý kết quả của lần gửi cuối cùng
  3. ngăn chặn các yêu cầu mới miễn là một yêu cầu khác vẫn đang chờ xử lý

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

Trong trường hợp của chúng tôi, chúng tôi đã quyết định sử dụng phương pháp số 3 vì nó tạo ra ít tải hơn cho máy chủ. Nhưng tôi không chắc chắn 100% nếu jQuery đảm bảo lệnh gọi của phương thức .complete () -, điều này có thể tạo ra tình huống bế tắc. Trong các thử nghiệm của chúng tôi, chúng tôi không thể tái tạo một tình huống như vậy.


36

Nó luôn luôn là thực hành tốt nhất để làm một cái gì đó như thế này.

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

Nhưng sẽ tốt hơn nhiều nếu bạn kiểm tra câu lệnh if để kiểm tra xem yêu cầu ajax có null hay không.


2
Tôi cũng kiểm tra xem một yêu cầu đã chạy chưa, nhưng tôi sử dụng boolean, vì nó nhẹ hơn.
Xin bấm vào đây

15

Chỉ cần gọi xhr. hủy bỏ () cho dù đó là đối tượng ajax jquery hoặc đối tượng XMLHTTPRequest riêng.

thí dụ:

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

13

Tôi đang thực hiện một giải pháp tìm kiếm trực tiếp và cần hủy các yêu cầu đang chờ xử lý có thể mất nhiều thời gian hơn yêu cầu mới nhất / mới nhất.

Trong trường hợp của tôi, tôi đã sử dụng một cái gì đó như thế này:

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

12

Như nhiều người trong luồng đã lưu ý, chỉ vì yêu cầu bị hủy bỏ ở phía máy khách, máy chủ vẫn sẽ xử lý yêu cầu. Điều này tạo ra tải không cần thiết trên máy chủ vì nó đang hoạt động mà chúng tôi đã bỏ nghe ở mặt trước.

Vấn đề tôi đang cố gắng giải quyết (mà những người khác cũng có thể gặp phải) là khi người dùng nhập thông tin vào trường nhập liệu, tôi muốn loại bỏ yêu cầu về loại cảm giác Google Instant.

Để tránh thực hiện các yêu cầu không cần thiết và để duy trì sự nhanh nhẹn của giao diện người dùng, tôi đã làm như sau:

var xhrQueue = [];
var xhrCount = 0;

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

    xhrQueue.push(xhrCount);

    setTimeout(function(){

        xhrCount = ++xhrCount;

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

    }, 150);

});

Điều này về cơ bản sẽ gửi một yêu cầu cứ sau 150ms (một biến mà bạn có thể tùy chỉnh theo nhu cầu của riêng mình). Nếu bạn gặp khó khăn trong việc hiểu chính xác những gì đang xảy ra ở đây, hãy đăng nhập xhrCountxhrQueuevào bảng điều khiển ngay trước khối if.


11

Chỉ cần sử dụng ajax.abort () ví dụ bạn có thể hủy bỏ mọi yêu cầu ajax đang chờ xử lý trước khi gửi một yêu cầu khác như thế này

//check for existing ajax request
if(ajax){ 
 ajax.abort();
 }
//then you make another ajax request
$.ajax(
 //your code here
  );

11

Bạn có thể hủy bỏ bất kỳ cuộc gọi ajax liên tục nào bằng cách sử dụng

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

10

không có cách nào đáng tin cậy để làm điều đó, và tôi thậm chí sẽ không thử nó, một khi yêu cầu được thực hiện; các chỉ cách để phản ứng một cách hợp lý là để bỏ qua các phản ứng.

trong hầu hết các trường hợp, điều này có thể xảy ra trong các tình huống như: người dùng nhấp quá thường xuyên vào nút kích hoạt nhiều XHR liên tiếp, ở đây bạn có nhiều tùy chọn, hoặc chặn nút cho đến khi XHR được trả lại hoặc thậm chí không kích hoạt XHR mới trong khi người khác đang chạy gợi ý người dùng dựa lưng - hoặc loại bỏ bất kỳ phản hồi XHR đang chờ xử lý nào nhưng gần đây.


7

Đoạn mã sau đây cho thấy bắt đầu cũng như hủy bỏ yêu cầu 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
Vui lòng cung cấp một lời giải thích về cách này giải quyết câu hỏi. Điều này sẽ giúp OP và những người tìm kiếm khác trong tương lai.
SnareChops

5

Tôi gặp vấn đề về bỏ phiếu và một khi trang đã đóng, cuộc thăm dò vẫn tiếp tục, vì lý do của tôi, người dùng sẽ bỏ lỡ một bản cập nhật vì giá trị mysql được đặt trong 50 giây tiếp theo sau khi đóng trang, mặc dù tôi đã giết yêu cầu ajax, tôi tìm ra xung quanh, sử dụng $ _SESSION để đặt var sẽ không cập nhật trong cuộc thăm dò ý kiến ​​cho đến khi nó kết thúc và một cái mới đã bắt đầu, vì vậy những gì tôi đã làm là đặt giá trị trong cơ sở dữ liệu của mình là 0 = offpage, trong khi tôi bỏ phiếu tôi truy vấn hàng đó và trả về false; khi đó là 0 khi truy vấn trong bỏ phiếu sẽ cho bạn các giá trị hiện tại rõ ràng ...

Tôi hy vọng điều này đã giúp


5

Nếu xhr.abort(); nguyên nhân tải lại trang,

Sau đó, bạn có thể đặt onreadystatechangetrước khi hủy bỏ để ngăn chặn:

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

4

Tôi đã chia sẻ một bản demo minh họa cách hủy yêu cầu AJAX-- nếu dữ liệu không được trả về từ máy chủ trong thời gian chờ được xác định trước.

HTML:

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

MÃ SỐ:

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
$.ajaxcung cấp một timeouttùy chọn để bạn không cần phải viết riêng của bạn. Đơn giản chỉ cần sử dụng ..., data: {...}, timeout: waitTime,....
Bram Vanroy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.