Bagaimana cara membatalkan / membatalkan permintaan AJAX jQuery?

244

Saya memiliki permintaan AJAX yang akan dibuat setiap 5 detik. Tetapi masalahnya adalah sebelum permintaan AJAX jika permintaan sebelumnya tidak selesai, saya harus membatalkan permintaan itu dan membuat permintaan baru.

Kode saya kira-kira seperti ini, bagaimana mengatasi masalah ini?

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

    var interval = setInterval(fn, 500);
);
pengguna556673
sumber
5
Pertanyaan Anda menyatakan bahwa permintaan harus dilakukan setiap 5 detik, tetapi kodenya menggunakan 500 ms = 0,5 dtk.
geon

Jawaban:

355

Metode jquery ajax mengembalikan objek XMLHttpRequest . Anda dapat menggunakan objek ini untuk membatalkan permintaan.

XMLHttpRequest memiliki metode batalkan , yang membatalkan permintaan, tetapi jika permintaan telah dikirim ke server maka server akan memproses permintaan bahkan jika kami membatalkan permintaan tetapi klien tidak akan menunggu / menangani respons.

Objek xhr juga berisi readyState yang berisi keadaan permintaan (UNSENT-0, OPENED-1, HEADERS_RECEIVED-2, LOADING-3 dan DONE-4). kita dapat menggunakan ini untuk memeriksa apakah permintaan sebelumnya selesai.

$(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);
);
Arun P Johny
sumber
60
@romkyns Perbedaannya adalah properti di readystateatas dan di readyStatebawah, karakter sdikapitalisasi dalam jQuery 1.5
Arun P Johny
Saya bertanya-tanya apa yang terjadi jika readyState adalah "LOADING-3" dan kami batal? Data dikirim ke server, dan diproses atau tidak. Kita tidak akan tahu ...: S
inf3rno
7
Btw, saya pikir pemeriksaan readyState tidak perlu, karena ditangguhkan dan setelah diselesaikan atau ditolak tidak akan menjalankan yang lain. Jadi if (xhr) xhr.abort();akan bekerja dengan baik juga.
Ciantic
2
W3 tidak pernah digunakan tidak dikapitalisasi readystatedalam dokumentasinya. Itu selalu dikapitalisasi readyStatedan jquery (sebelum atau sesudah 1,5) benar sesuai dengan spesifikasi w3.
Arashsoft
@ArunPJohny, dapatkah Anda menjawab pertanyaan ini stackoverflow.com/questions/49801146/…
Krishna Jonnalagadda
6

Saat Anda membuat permintaan ke server, minta ia memeriksa untuk melihat apakah suatu kemajuan bukanlah nol (atau mengambil data itu) terlebih dahulu. Jika mengambil data, batalkan permintaan sebelumnya dan mulai yang baru.

var progress = null

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

Saya tahu ini mungkin sedikit terlambat tetapi saya mengalami masalah serupa di mana memanggil metode abort tidak benar-benar membatalkan permintaan. alih-alih, peramban masih menunggu respons yang tidak pernah digunakan. kode ini menyelesaikan masalah itu.

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

Mengapa Anda harus membatalkan permintaan?

Jika setiap permintaan membutuhkan waktu lebih dari lima detik, apa yang akan terjadi?

Anda tidak boleh membatalkan permintaan jika parameter yang lewat dengan permintaan tidak berubah. misalnya: - permintaan untuk mengambil data notifikasi. Dalam situasi seperti itu, Pendekatan yang bagus adalah menetapkan permintaan baru hanya setelah menyelesaikan permintaan Ajax sebelumnya.

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

);
Habeeb Perwad
sumber
5
Ini ide yang buruk. Saat memulai panggilan baru, Anda tidak ingin acara lengkap dipecat dari panggilan sebelumnya. Anda mungkin mendapatkan hasil yang sangat aneh dengan pendekatan ini.
Webberig
1

Anda dapat menggunakan jquery-validate.js. Berikut ini adalah cuplikan kode dari 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);
    };
}

Sehingga Anda hanya perlu mengatur mode parameter untuk dibatalkan ketika Anda membuat permintaan ajax.

Ref: https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.14.0/jquery.validate.js

zawhtut
sumber
0

jQuery: Gunakan ini sebagai titik awal - sebagai inspirasi. Saya memecahkannya seperti ini: (ini bukan solusi yang sempurna, itu hanya membatalkan contoh terakhir dan kode 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.
BananaAcid
sumber
0

Buat fungsi untuk memanggil API Anda. Dalam fungsi ini kami mendefinisikan permintaan callApiRequest = $.get(...- meskipun ini adalah definisi dari suatu variabel, permintaan tersebut dipanggil segera, tetapi sekarang kami memiliki permintaan yang didefinisikan sebagai variabel. Sebelum permintaan dipanggil, kami memeriksa apakah variabel kami ditentukan typeof(callApiRequest) != 'undefined'dan juga jika sedang menunggu suggestCategoryRequest.state() == 'pending'- jika keduanya benar, kami .abort()permintaan yang akan mencegah keberhasilan callback berjalan.

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

    });
}

Server / API Anda mungkin tidak mendukung membatalkan permintaan (bagaimana jika API sudah mengeksekusi beberapa kode?), Tetapi panggilan balik javascript tidak akan diaktifkan. Ini berguna, ketika misalnya Anda memberikan saran input kepada pengguna, seperti input hashtag.

Anda selanjutnya dapat memperluas fungsi ini dengan menambahkan definisi panggilan balik kesalahan - apa yang harus terjadi jika permintaan dibatalkan.

Kasing penggunaan umum untuk cuplikan ini adalah input teks yang diaktifkan saat keypressacara. Anda dapat menggunakan batas waktu, untuk mencegah pengiriman (sebagian) permintaan yang harus Anda batalkan .abort().

mate.gwozdz
sumber
-7

Anda juga harus memeriksa readyState 0. Karena ketika Anda menggunakan xhr.abort () fungsi ini mengatur readyState ke 0 pada objek ini, dan centang if Anda akan selalu benar - 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);
); 
programmer
sumber
2
Apakah Anda menyalin dan menempelkan jawaban Arun? Karena kemungkinan dua blok kode seperti itu persis sama, spasi dan semua ...
@ user2700923 Posnya tidak persis sama. Maksudnya adalah bahwa kita juga harus memeriksa readyState 0. Namun ini akan lebih sesuai sebagai komentar untuk jawaban Arun.
Stefan