Làm cách nào để hủy / hủy yêu cầu AJAX của jQuery?


244

Tôi có một yêu cầu AJAX sẽ được thực hiện cứ sau 5 giây. Nhưng vấn đề là trước yêu cầu AJAX nếu yêu cầu trước đó chưa hoàn thành Tôi đã hủy bỏ yêu cầu đó và đưa ra yêu cầu mới.

Mã của tôi là một cái gì đó như thế này, làm thế nào để giải quyết vấn đề này?

$(document).ready(
    var fn = function(){
        $.ajax({
            url: 'ajax/progress.ftl',
            success: function(data) {
                //do something
            }
        });
    };

    var interval = setInterval(fn, 500);
);


5
Câu hỏi của bạn nêu yêu cầu sẽ xảy ra cứ sau 5 giây, nhưng mã sử dụng 500 ms = 0,5 s.
geon

Câu trả lời:


355

Phương thức jjery ajax trả về XMLHttpRequest đối tượng . Bạn có thể sử dụng đối tượng này để hủy yêu cầu.

XMLHttpRequest có một phương thức hủy bỏ , hủy bỏ yêu cầu, nhưng nếu yêu cầu đã được gửi đến máy chủ thì máy chủ sẽ xử lý yêu cầu ngay cả khi chúng tôi hủy yêu cầu nhưng khách hàng sẽ không chờ / xử lý phản hồi.

Đối tượng xhr cũng chứa readyState chứa trạng thái yêu cầu (UNSENT-0, OPENED-1, HEADERS_RECEIVED-2, LOADING-3 và DONE-4). chúng ta có thể sử dụng điều này để kiểm tra xem yêu cầu trước đó đã được hoàn thành chưa.

$(document).ready(
    var xhr;

    var fn = function(){
        if(xhr && xhr.readyState != 4){
            xhr.abort();
        }
        xhr = $.ajax({
            url: 'ajax/progress.ftl',
            success: function(data) {
                //do something
            }
        });
    };

    var interval = setInterval(fn, 500);
);

60
@romkyns Sự khác biệt là thuộc tính readystatetrên và readyStatedưới, ký tự sđược viết hoa trong jQuery 1.5
Arun P Johny

Tôi đã tự hỏi điều gì xảy ra nếu readyState là "LOADING-3" và chúng tôi hủy bỏ? Dữ liệu được gửi đến máy chủ, và nó có được xử lý hay không. Chúng tôi sẽ không biết ...: S
inf3rno

7
Btw, tôi nghĩ rằng kiểm tra readyState là không cần thiết, vì nó bị hoãn lại và một khi nó được giải quyết hoặc từ chối, nó sẽ không chạy các cái khác. Vì vậy, if (xhr) xhr.abort();sẽ làm việc tốt quá.
Ciantic

2
W3 không bao giờ được sử dụng không viết hoa readystatetrong tài liệu của nó. Nó luôn được viết hoa readyStatevà jquery (trước hoặc sau 1.5) khớp chính xác với đặc điểm kỹ thuật của w3.
Arashsoft

@ArunPJohny, bạn có thể vui lòng đặt câu hỏi này stackoverflow.com/questions/49801146/
Kẻ

6

Khi bạn thực hiện một yêu cầu đến một máy chủ, hãy kiểm tra xem liệu tiến trình không phải là null (hoặc tìm nạp dữ liệu đó) trước. Nếu nó đang tìm nạp dữ liệu, hãy hủy yêu cầu trước đó và bắt đầu yêu cầu mới.

var progress = null

function fn () {    
    if (progress) {
        progress.abort();
    }
    progress = $.ajax('ajax/progress.ftl', {
        success: function(data) {
            //do something
            progress = null;
        }
    });
}

5

Tôi biết điều này có thể hơi muộn nhưng tôi gặp vấn đề tương tự khi gọi phương thức hủy bỏ không thực sự hủy bỏ yêu cầu. thay vào đó, trình duyệt vẫn đang chờ phản hồi mà nó không bao giờ sử dụng. mã này đã giải quyết vấn đề đó.

 try {
        xhr.onreadystatechange = null;
        xhr.abort();
} catch (e) {}

1

Tại sao bạn nên hủy bỏ yêu cầu?

Nếu mỗi yêu cầu mất hơn năm giây, điều gì sẽ xảy ra?

Bạn không nên hủy yêu cầu nếu tham số truyền với yêu cầu không thay đổi. ví dụ: - yêu cầu dành cho việc truy xuất dữ liệu thông báo. Trong các tình huống như vậy, Cách tiếp cận tốt đẹp là chỉ đặt một yêu cầu mới sau khi hoàn thành yêu cầu Ajax trước đó.

$(document).ready(

    var fn = function(){

        $.ajax({
            url: 'ajax/progress.ftl',
            success: function(data) {
                //do something
            },

            complete: function(){setTimeout(fn, 500);}
        });
    };

     var interval = setTimeout(fn, 500);

);

5
Đây là một ý tưởng tồi. Khi bắt đầu một cuộc gọi mới, bạn không muốn sự kiện hoàn thành bị hủy bỏ cuộc gọi trước đó. Bạn có thể nhận được kết quả rất kỳ lạ với phương pháp này.
Webberig

1

Bạn có thể sử dụng jquery-validate.js. Sau đây là đoạn mã từ jquery-validate.js.

// ajax mode: abort
// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()

var pendingRequests = {},
    ajax;
// Use a prefilter if available (1.5+)
if ( $.ajaxPrefilter ) {
    $.ajaxPrefilter(function( settings, _, xhr ) {
        var port = settings.port;
        if ( settings.mode === "abort" ) {
            if ( pendingRequests[port] ) {
                pendingRequests[port].abort();
            }
            pendingRequests[port] = xhr;
        }
    });
} else {
    // Proxy ajax
    ajax = $.ajax;
    $.ajax = function( settings ) {
        var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
            port = ( "port" in settings ? settings : $.ajaxSettings ).port;
        if ( mode === "abort" ) {
            if ( pendingRequests[port] ) {
                pendingRequests[port].abort();
            }
            pendingRequests[port] = ajax.apply(this, arguments);
            return pendingRequests[port];
        }
        return ajax.apply(this, arguments);
    };
}

Vì vậy, bạn chỉ cần đặt chế độ tham số để hủy bỏ khi bạn thực hiện yêu cầu ajax.

Tham chiếu: https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.14.0/jquery.validate.js


0

jQuery: Sử dụng điều này như một điểm khởi đầu - như nguồn cảm hứng. Tôi đã giải quyết nó như thế này: (đây không phải là một giải pháp hoàn hảo, nó chỉ hủy bỏ trường hợp cuối cùng và là mã WIP)

var singleAjax = function singleAjax_constructor(url, params) {
    // remember last jQuery's get request
    if (this.lastInstance) {
        this.lastInstance.abort();  // triggers .always() and .fail()
        this.lastInstance = false;
    }

    // how to use Deferred : http://api.jquery.com/category/deferred-object/
    var $def = new $.Deferred();

    // pass the deferrer's request handlers into the get response handlers
    this.lastInstance = $.get(url, params)
        .fail($def.reject)         // triggers .always() and .fail()
        .success($def.resolve);    // triggers .always() and .done()

    // return the deferrer's "control object", the promise object
    return $def.promise();
}


// initiate first call
singleAjax('/ajax.php', {a: 1, b: 2})
    .always(function(a,b,c) {console && console.log(a,b,c);});

// second call kills first one
singleAjax('/ajax.php', {a: 1, b: 2})
    .always(function(a,b,c) {console && console.log(a,b,c);});
    // here you might use .always() .fail() .success() etc.

0

Tạo một hàm để gọi API của bạn. Trong hàm này, chúng tôi xác định yêu cầu callApiRequest = $.get(...- mặc dù đây là định nghĩa của biến, yêu cầu được gọi ngay lập tức, nhưng bây giờ chúng tôi có yêu cầu được xác định là biến. Trước khi yêu cầu được gọi, chúng tôi kiểm tra xem biến của chúng tôi có được xác định typeof(callApiRequest) != 'undefined'hay không và nếu nó đang chờ xử lý suggestCategoryRequest.state() == 'pending'- nếu cả hai đều đúng, chúng tôi .abort()sẽ yêu cầu ngăn chặn cuộc gọi lại thành công.

// We need to wrap the call in a function
callApi = function () {

    //check if request is defined, and status pending
    if (typeof(callApiRequest) != 'undefined'
        && suggestCategoryRequest.state() == 'pending') {

        //abort request
        callApiRequest.abort()

    }

    //define and make request
    callApiRequest = $.get("https://example.com", function (data) {

        data = JSON.parse(data); //optional (for JSON data format)
        //success callback

    });
}

Máy chủ / API của bạn có thể không hỗ trợ hủy bỏ yêu cầu (điều gì xảy ra nếu API đã thực thi một số mã?), Nhưng cuộc gọi lại javascript sẽ không kích hoạt. Điều này rất hữu ích, ví dụ khi bạn đang cung cấp các đề xuất đầu vào cho người dùng, chẳng hạn như đầu vào hashtags.

Bạn có thể mở rộng thêm chức năng này bằng cách thêm định nghĩa về gọi lại lỗi - điều gì sẽ xảy ra nếu yêu cầu bị hủy bỏ.

Trường hợp sử dụng phổ biến cho đoạn mã này sẽ là một kiểu nhập văn bản kích hoạt keypresssự kiện. Bạn có thể sử dụng thời gian chờ, để ngăn việc gửi (một số) yêu cầu mà bạn sẽ phải hủy .abort().


-7

Bạn cũng nên kiểm tra readyState 0. Bởi vì khi bạn sử dụng xhr.abort (), hàm này đặt readyState thành 0 trong đối tượng này và kiểm tra if của bạn sẽ luôn đúng - readyState! = 4

$(document).ready(
    var xhr;

    var fn = function(){
        if(xhr && xhr.readyState != 4 && xhr.readyState != 0){
            xhr.abort();
        }
        xhr = $.ajax({
            url: 'ajax/progress.ftl',
            success: function(data) {
                //do something
            }
        });
    };

    var interval = setInterval(fn, 500);
); 

2
Bạn đã sao chép và dán câu trả lời của Arun? Bởi vì khả năng hai khối mã giống hệt nhau, khoảng cách và tất cả ...

@ user2700923 Bài đăng của anh ấy không hoàn toàn giống nhau. Quan điểm của ông là chúng ta cũng nên kiểm tra readyState 0. Tuy nhiên, điều này sẽ phù hợp hơn khi nhận xét câu trả lời của Arun.
Stefan
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.