Batalkan permintaan Ajax menggunakan jQuery

1827

Dengan menggunakan jQuery, bagaimana saya bisa membatalkan / membatalkan permintaan Ajax yang belum saya terima jawabannya?

suam-suam kuku
sumber
2
Mungkin saya salah paham pertanyaannya, tetapi tidak bisakah Anda menggunakan saja $.ajaxStop?
Luke Madhanga
17
@LukeMadhanga; Saya pikir ajaxStophanya mendeteksi ketika semua permintaan AJAX selesai, itu tidak menghentikan permintaan. Dalam pengalaman saya, Anda akan menggunakannya seperti ini: $(document).ajaxStop(function(){alert("All done")}). Menggunakan .abort()adalah pilihan terbaik.
TheCarver

Jawaban:

1744

Sebagian besar metode jQuery Ajax mengembalikan objek XMLHttpRequest (atau yang setara), jadi Anda bisa menggunakannya abort().

Lihat dokumentasi:

  • Metode abort ( MSDN ). Membatalkan permintaan HTTP saat ini.
  • batalkan () ( MDN ). Jika permintaan sudah dikirim, metode ini akan membatalkan permintaan.
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()

UPDATE: Pada jQuery 1.5 objek yang dikembalikan adalah pembungkus untuk objek XMLHttpRequest asli yang disebut jqXHR. Objek ini muncul untuk mengekspos semua properti dan metode asli sehingga contoh di atas masih berfungsi. Lihat Objek jqXHR (dokumentasi API jQuery).

UPDATE 2: Pada jQuery 3, metode ajax sekarang mengembalikan janji dengan metode tambahan (seperti batalkan), jadi kode di atas masih berfungsi, meskipun objek yang dikembalikan bukan xhrlagi. Lihat blog 3.0 di sini .

UPDATE 3 : xhr.abort()masih berfungsi di jQuery 3.x. Jangan menganggap pembaruan 2 sudah benar. Info lebih lanjut tentang repositori jQuery Github .

meouw
sumber
12
Ini seperti mengklik tombol 'berhenti' di browser Anda. Itu membatalkan permintaan. Anda kemudian dapat menggunakan kembali objek XHR yang sama untuk permintaan lain.
meouw
65
@brad Sayangnya, aborttidak menutup koneksi yang ada dengan server, jadi successmasih akan dipanggil. Ini sangat bermasalah untuk implementasi Comet dengan polling yang panjang.
pepkin88
6
@ ErrWalter Anda dapat mengirim permintaan lain yang membatalkan yang sebelumnya.
Asad Saeeduddin
8
Dalam pengujian saya, permintaan dibatalkan di browser, tetapi metode .fail () dipanggil dengan jqXHR, status = 0, dan jqXHR, statusMessage = "batalkan"
BJ Safdie
9
.abort()masih bekerja untuk saya di jQuery 3.2.1. Komentar ini dalam masalah github terkait oleh anggota tim inti jQuery tampaknya menyiratkan bahwa jawaban ini salah dan .abort() itu tidak dihapus.
alarive
117

Anda tidak dapat mengingat permintaan tetapi Anda dapat menetapkan nilai batas waktu setelah mana tanggapan akan diabaikan. Lihat halaman ini untuk opsi jquery AJAX. Saya percaya bahwa panggilan balik kesalahan Anda akan dipanggil jika periode batas waktu terlampaui. Sudah ada batas waktu default pada setiap permintaan AJAX.

Anda juga dapat menggunakan batalkan () metode pada objek permintaan tapi, sementara itu akan menyebabkan klien untuk berhenti mendengarkan untuk acara tersebut, itu mungkin mungkin tidak akan menghentikan server dari memprosesnya.

tvanfosson
sumber
74

Ini asinkron permintaan yang tidak , artinya setelah dikirim, itu ada.

Jika server Anda memulai operasi yang sangat mahal karena permintaan AJAX, yang terbaik yang dapat Anda lakukan adalah membuka server Anda untuk mendengarkan permintaan pembatalan, dan mengirim permintaan AJAX terpisah yang memberitahukan server untuk menghentikan apa pun yang dilakukannya.

Jika tidak, abaikan saja respons AJAX.

Yuval Adam
sumber
48
Dalam konteks ini, asinkron berarti permintaan tidak mengganggu alur skrip. Browser sekarang memiliki kemampuan untuk membatalkan permintaan sebelum waktunya sebelum permintaan selesai.
ElephantHunter
4
Bagaimana kami bisa mengirim permintaan batal ke server? Saya tidak mengerti bagaimana server akan tahu permintaan mana yang harus berhenti diproses? Bisakah Anda memberi contoh? Terima kasih.
Lucky Soni
3
@ LuckySoni, Elephanthunter hanya membahas sisi klien. Server tidak akan terpengaruh oleh permintaan
.abort
4
@ Kloar, jika permintaan belum diterima oleh server (mis. Permintaan banyak bagian yang besar), klien dapat menutup soket, dan server akan terpengaruh.
putih
4
PHP memeriksa permintaan yang dibatalkan secara otomatis, dan berakhir secara otomatis juga. lihat php.net/manual/en/function.ignore-user-abort.php
hanshenrik
68

Simpan panggilan yang Anda lakukan dalam array, lalu panggil xhr.abort () di masing-masingnya.

CAVEAT BESAR: Anda dapat membatalkan permintaan, tetapi itu hanya sisi klien. Sisi server masih dapat memproses permintaan. Jika Anda menggunakan sesuatu seperti PHP atau ASP dengan data sesi, data sesi dikunci sampai ajax selesai. Jadi, agar pengguna dapat terus menjelajahi situs web, Anda harus menelepon session_write_close (). Ini menyimpan sesi dan membuka kunci sehingga halaman lain yang menunggu untuk melanjutkan akan dilanjutkan. Tanpa ini, beberapa halaman dapat menunggu kunci dihapus.

Tei
sumber
karena Anda selalu membatalkan yang sebelumnya, tidak bisakah Anda selalu melakukan itu? (dan tidak perlu menggunakan array)
nonopolaritas
60

Permintaan AJAX mungkin tidak lengkap dalam urutan dimulai. Alih-alih membatalkan, Anda dapat memilih untuk mengabaikan semua respons AJAX kecuali yang paling baru:

  • Buat penghitung
  • Tambahkan penghitung saat Anda memulai permintaan AJAX
  • Gunakan nilai penghitung saat ini untuk "mencap" permintaan
  • Dalam panggilan balik sukses membandingkan cap dengan counter untuk memeriksa apakah itu permintaan terbaru

Garis besar kode yang kasar:

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

Demo di jsFiddle

Salman A
sumber
Karena peringatan membatalkan permintaan XHR (lihat komentar lain di halaman ini), ini mungkin merupakan pilihan terbaik dan paling sederhana.
Quinn Comendant
41

Kami hanya harus mengatasi masalah ini dan menguji tiga pendekatan yang berbeda.

  1. membatalkan permintaan seperti yang disarankan oleh @meouw
  2. melaksanakan semua permintaan tetapi hanya memproses hasil dari pengiriman terakhir
  3. Mencegah permintaan baru selama yang lain masih menunggu

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

Dalam kasus kami, kami memutuskan untuk menggunakan pendekatan # 3 karena menghasilkan lebih sedikit beban untuk server. Tapi saya tidak 100% yakin jika jQuery menjamin panggilan metode .complete () -, ini bisa menghasilkan situasi jalan buntu. Dalam pengujian kami, kami tidak dapat mereproduksi situasi seperti itu.

oyophant
sumber
36

Itu selalu praktik terbaik untuk melakukan sesuatu seperti ini.

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

Tetapi jauh lebih baik jika Anda memeriksa pernyataan if untuk memeriksa apakah permintaan ajax adalah nol atau tidak.

Tharindu Kumara
sumber
2
Saya juga memeriksa apakah permintaan sudah berjalan, tetapi saya menggunakan boolean, karena lebih ringan.
Zesty
15

Panggil saja xhr. batalkan () apakah itu objek jquery ajax atau objek XMLHTTPRequest asli.

contoh:

//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);
cuixiping
sumber
13

Saya sedang melakukan solusi pencarian langsung dan perlu membatalkan permintaan yang tertunda yang mungkin memakan waktu lebih lama dari permintaan terbaru / terbaru.

Dalam kasus saya, saya menggunakan sesuatu seperti ini:

//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 
Billy
sumber
12

Seperti yang dicatat oleh banyak orang di utas, hanya karena permintaan dibatalkan di sisi klien, server masih akan memproses permintaan tersebut. Ini menciptakan beban yang tidak perlu di server karena melakukan pekerjaan yang kami berhenti mendengarkan di front-end.

Masalah yang saya coba selesaikan (yang mungkin juga dijalankan oleh orang lain) adalah ketika pengguna memasukkan informasi dalam bidang input, saya ingin menjalankan permintaan untuk jenis nuansa Google Instan.

Untuk menghindari memecat permintaan yang tidak perlu dan untuk menjaga kenyamanan front-end, saya melakukan hal berikut:

var xhrQueue = [];
var xhrCount = 0;

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

    xhrQueue.push(xhrCount);

    setTimeout(function(){

        xhrCount = ++xhrCount;

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

    }, 150);

});

Ini pada dasarnya akan mengirim satu permintaan setiap 150ms (variabel yang dapat Anda sesuaikan untuk kebutuhan Anda sendiri). Jika Anda mengalami kesulitan memahami apa yang sebenarnya terjadi di sini, log xhrCountdan xhrQueueke konsol sebelum jika blok.

brianrhea
sumber
11

Cukup gunakan ajax.abort () misalnya Anda dapat membatalkan permintaan ajax yang tertunda sebelum mengirim yang lain seperti ini

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

Anda dapat membatalkan panggilan ajax berkelanjutan dengan menggunakan ini

<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>
Soubhagya Kumar Barik
sumber
10

tidak ada cara yang dapat diandalkan untuk melakukannya, dan saya bahkan tidak akan mencobanya, begitu permintaan sedang berjalan; satu - satunya cara untuk bereaksi secara wajar adalah dengan mengabaikan respons.

dalam kebanyakan kasus, itu dapat terjadi dalam situasi seperti: pengguna mengklik terlalu sering pada tombol yang memicu banyak XHR berturut-turut, di sini Anda memiliki banyak pilihan, baik memblokir tombol sampai XHR dikembalikan, atau bahkan tidak memicu XHR baru sementara yang lain sedang menjalankan petunjuk pengguna untuk bersandar - atau membuang respons XHR yang tertunda kecuali yang terbaru.

datangGameSome
sumber
7

Kode berikut menunjukkan memulai serta membatalkan permintaan 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!" >
zloctb
sumber
5
Harap berikan penjelasan tentang bagaimana ini menyelesaikan pertanyaan. Ini akan membantu OP dan pencari masa depan lainnya.
SnareChops
5

Saya memiliki masalah pemungutan suara dan setelah halaman ditutup, pemungutan suara berlanjut sehingga karena saya pengguna akan melewatkan pembaruan karena nilai mysql sedang ditetapkan untuk 50 detik berikutnya setelah penutupan halaman, meskipun saya membunuh permintaan ajax, saya mencari tahu, menggunakan $ _SESSION untuk menetapkan var tidak akan memperbarui dalam polling sendiri sampai berakhir dan yang baru telah dimulai, jadi apa yang saya lakukan adalah menetapkan nilai dalam database saya sebagai 0 = offpage, sementara saya polling, saya query baris itu dan mengembalikan false; saat ini 0 karena kueri dalam polling akan memberi Anda nilai saat ini jelas ...

Saya harap ini membantu

Marcus
sumber
5

Jika xhr.abort(); menyebabkan pemuatan ulang halaman,

Kemudian Anda dapat mengatur onreadystatechangesebelum batal untuk mencegah:

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

Saya telah membagikan demo yang menunjukkan cara membatalkan permintaan AJAX - jika data tidak dikembalikan dari server dalam waktu tunggu yang telah ditentukan.

HTML:

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

KODE JS:

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);   
});
Ganesh
sumber
1
$.ajaxmenyediakan timeoutopsi sehingga Anda tidak perlu menulis sendiri. Cukup gunakan ..., data: {...}, timeout: waitTime,....
Bram Vanroy