Hentikan semua permintaan ajax aktif di jQuery

216

Saya punya masalah, ketika mengirimkan formulir semua permintaan ajax aktif gagal, dan itu memicu peristiwa kesalahan.

Bagaimana cara menghentikan semua permintaan ajax aktif di jQuery tanpa trigerring error event?

umpirsky
sumber

Jawaban:

273

Setiap kali Anda membuat permintaan ajax, Anda bisa menggunakan variabel untuk menyimpannya:

var request = $.ajax({
    type: 'POST',
    url: 'someurl',
    success: function(result){}
});

Kemudian Anda dapat membatalkan permintaan:

request.abort();

Anda bisa menggunakan larik pencatatan array dari semua permintaan ajax yang tertunda dan batalkan jika perlu.

Darin Dimitrov
sumber
THXs, saya menambahkan FLAG karena saya menggunakan beberapa permintaan pada waktu yang sama
jcho360
di sini adalah contoh kerja sederhana: stackoverflow.com/a/42312101/3818394
Dharmesh patel
saya memiliki fungsi panggilan ajax bagaimana saya bisa membatalkannya?
Kalariya_M
Variabel harus dinyatakan global untuk mengaksesnya dari fungsi lain ketika panggilan ajax sedang berlangsung. contoh: proses unggah multi-file.
Clain Dsilva
180

Cuplikan berikut memungkinkan Anda mempertahankan daftar ( kumpulan ) permintaan dan membatalkan semuanya jika diperlukan. Terbaik untuk ditempatkan di <HEAD>html Anda, sebelum panggilan AJAX lainnya dibuat.

<script type="text/javascript">
    $(function() {
        $.xhrPool = [];
        $.xhrPool.abortAll = function() {
            $(this).each(function(i, jqXHR) {   //  cycle through list of recorded connection
                jqXHR.abort();  //  aborts connection
                $.xhrPool.splice(i, 1); //  removes from list by index
            });
        }
        $.ajaxSetup({
            beforeSend: function(jqXHR) { $.xhrPool.push(jqXHR); }, //  annd connection to list
            complete: function(jqXHR) {
                var i = $.xhrPool.indexOf(jqXHR);   //  get index for current connection completed
                if (i > -1) $.xhrPool.splice(i, 1); //  removes from list by index
            }
        });
    })
</script>
mkmore
sumber
2
@mkmurray - pada inisialisasi di IE8 saya sepertinya mengerti Object doesn't support property or method 'indexOf'? Saya menduga itu mungkin stackoverflow.com/a/2608601/181971 atau mungkin hanya bertukar ke stackoverflow.com/a/2608618/181971 ?
Tim
3
@ Grr benar, lihat jawabannya dan periksa dokumen untuk ajaxSetup .
kzfabi
@Tim - seperti yang disarankan Steven, alih-alih var index = $ .xhrPool.indexOf (jqXHR); gunakan: var index = $ .inArray (jqXHR, $ .xhrPool);
Christopher
1
@mkmurray: Ini menunjukkan TypeError: jqXHR.abort bukan fungsi untuk saya. :(
Shesha
Ada sedikit kesalahan logis dalam metode abortAll, yang diperbaiki di sini dalam jawaban ini stackoverflow.com/a/45500874/1041341
Sarin JS
122

Menggunakan ajaxSetup tidak benar , seperti yang dicatat pada halaman . Ini hanya mengatur default, dan jika beberapa permintaan menimpanya, akan ada kekacauan.

Saya jauh terlambat ke pesta, tetapi hanya untuk referensi di masa depan jika seseorang mencari solusi untuk masalah yang sama, inilah tugas saya, terinspirasi oleh dan sebagian besar identik dengan jawaban sebelumnya, tetapi lebih lengkap

// Automatically cancel unfinished ajax requests 
// when the user navigates elsewhere.
(function($) {
  var xhrPool = [];
  $(document).ajaxSend(function(e, jqXHR, options){
    xhrPool.push(jqXHR);
  });
  $(document).ajaxComplete(function(e, jqXHR, options) {
    xhrPool = $.grep(xhrPool, function(x){return x!=jqXHR});
  });
  var abort = function() {
    $.each(xhrPool, function(idx, jqXHR) {
      jqXHR.abort();
    });
  };

  var oldbeforeunload = window.onbeforeunload;
  window.onbeforeunload = function() {
    var r = oldbeforeunload ? oldbeforeunload() : undefined;
    if (r == undefined) {
      // only cancel requests if there is no prompt to stay on the page
      // if there is a prompt, it will likely give the requests enough time to finish
      abort();
    }
    return r;
  }
})(jQuery);
Grr
sumber
Bagaimana seseorang memanggil metode abort () dari fungsi lain?
Stan James
batalkan adalah fungsi, bukan metode. Anda menyebutnya dari dalam enkapsulasi yang sama secara normal, jika Anda perlu menggunakannya di luar enkapsulasi Anda dapat menghapus "var" sebelum nama fungsi dan itu akan menjadi funciton yang tersedia secara global
Trey
Hai, bisakah seseorang menjelaskan kapan r tidak akan ditentukan?
Varun
36

Inilah yang saya gunakan saat ini untuk mencapai itu.

$.xhrPool = [];
$.xhrPool.abortAll = function() {
  _.each(this, function(jqXHR) {
    jqXHR.abort();
  });
};
$.ajaxSetup({
  beforeSend: function(jqXHR) {
    $.xhrPool.push(jqXHR);
  }
});

Catatan: _.setiap underscore.js ada, tetapi jelas tidak perlu. Saya hanya malas dan saya tidak ingin mengubahnya menjadi $ .each (). 8P

Andy Ferra
sumber
2
Saya punya solusi yang sedikit dimodifikasi yang bekerja sangat baik yang baru saja saya posting.
mkmurray
7
Memori ini bocor. aboutAllharus menghapus elemen dari array. Plus ketika permintaan selesai, itu harus menghapus sendiri dari daftar.
Behrang Saeedzadeh
5
@BehrangSaeedzadeh Anda seharusnya juga memposting versi yang ditingkatkan.
mattsven
19

Berikan setiap permintaan xhr id unik dan simpan referensi objek dalam objek sebelum mengirim. Hapus referensi setelah permintaan xhr selesai.

Untuk membatalkan semua permintaan kapan saja:

$.ajaxQ.abortAll();

Mengembalikan id unik dari permintaan yang dibatalkan. Hanya untuk tujuan pengujian.

Fungsi kerja:

$.ajaxQ = (function(){
  var id = 0, Q = {};

  $(document).ajaxSend(function(e, jqx){
    jqx._id = ++id;
    Q[jqx._id] = jqx;
  });
  $(document).ajaxComplete(function(e, jqx){
    delete Q[jqx._id];
  });

  return {
    abortAll: function(){
      var r = [];
      $.each(Q, function(i, jqx){
        r.push(jqx._id);
        jqx.abort();
      });
      return r;
    }
  };

})();

Mengembalikan objek dengan fungsi tunggal yang dapat digunakan untuk menambahkan lebih banyak fungsi saat diperlukan.

refik
sumber
17

Saya merasa terlalu mudah untuk beberapa permintaan.

langkah1: tentukan variabel di bagian atas halaman:

  xhrPool = []; // no need to use **var**

step2: atur sebelumKirim dalam semua permintaan ajax:

  $.ajax({
   ...
   beforeSend: function (jqXHR, settings) {
        xhrPool.push(jqXHR);
    },
    ...

step3: gunakan di mana pun Anda inginkan:

   $.each(xhrPool, function(idx, jqXHR) {
          jqXHR.abort();
    });
Dharmesh patel
sumber
Memori ini bocor, seperti halnya stackoverflow.com/a/6618288/1772379 , dan untuk alasan yang persis sama.
Ben Johnson
Cara yang sangat mengerikan untuk menulis JavaScript.
Ozil
1
mungkin pada akhirnya Anda dapat menghapus / mengosongkan array xhrPool
space earth
6

Saya memperpanjang jawaban mkmurray dan SpYk3HH di atas sehingga xhrPool.abortAll dapat membatalkan semua permintaan yang tertunda dari url yang diberikan :

$.xhrPool = [];
$.xhrPool.abortAll = function(url) {
    $(this).each(function(i, jqXHR) { //  cycle through list of recorded connection
        console.log('xhrPool.abortAll ' + jqXHR.requestURL);
        if (!url || url === jqXHR.requestURL) {
            jqXHR.abort(); //  aborts connection
            $.xhrPool.splice(i, 1); //  removes from list by index
        }
    });
};
$.ajaxSetup({
    beforeSend: function(jqXHR) {
        $.xhrPool.push(jqXHR); //  add connection to list
    },
    complete: function(jqXHR) {
        var i = $.xhrPool.indexOf(jqXHR); //  get index for current connection completed
        if (i > -1) $.xhrPool.splice(i, 1); //  removes from list by index
    }
});
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    console.log('ajaxPrefilter ' + options.url);
    jqXHR.requestURL = options.url;
});

Penggunaannya sama kecuali abortAll yang sekarang secara opsional dapat menerima url sebagai parameter dan hanya akan membatalkan panggilan yang tertunda ke url itu

kofifus
sumber
5

Saya memiliki beberapa masalah dengan kode andy, tetapi itu memberi saya beberapa ide bagus. Masalah pertama adalah bahwa kita harus menghapus objek jqXHR yang berhasil diselesaikan. Saya juga harus memodifikasi fungsi abortAll. Ini kode kerja terakhir saya:

$.xhrPool = [];
$.xhrPool.abortAll = function() {
            $(this).each(function(idx, jqXHR) {
                        jqXHR.abort();
                        });
};
$.ajaxSetup({
    beforeSend: function(jqXHR) {
            $.xhrPool.push(jqXHR);
            }
});
$(document).ajaxComplete(function() {
            $.xhrPool.pop();
            });

Saya tidak suka cara ajaxComplete () dalam melakukan sesuatu. Tidak peduli bagaimana saya mencoba mengkonfigurasi .ajaxSetup itu tidak berfungsi.

Hampster
sumber
7
Saya pikir Anda mungkin menelepon pop pada permintaan yang salah jika mereka tidak menyelesaikannya dalam urutan tertentu?
jjmontes
1
Ya, Anda ingin melakukan slice, bukannya pop. Saya punya solusi yang sedikit dimodifikasi yang akan saya posting.
mkmurray
4

Saya telah memperbarui kode untuk membuatnya berfungsi untuk saya

$.xhrPool = [];
$.xhrPool.abortAll = function() {
    $(this).each(function(idx, jqXHR) {
        jqXHR.abort();
    });
    $(this).each(function(idx, jqXHR) {
        var index = $.inArray(jqXHR, $.xhrPool);
        if (index > -1) {
            $.xhrPool.splice(index, 1);
        }
    });
};

$.ajaxSetup({
    beforeSend: function(jqXHR) {
        $.xhrPool.push(jqXHR);
    },
    complete: function(jqXHR) {
        var index = $.inArray(jqXHR, $.xhrPool);
        if (index > -1) {
            $.xhrPool.splice(index, 1);
        }
    }
});
Steven
sumber
4

Melemparkan topiku. Menawarkan abortdan removemetode terhadap xhrPoolarray, dan tidak rentan terhadap masalah dengan ajaxSetuppenggantian.

/**
 * Ajax Request Pool
 * 
 * @author Oliver Nassar <[email protected]>
 * @see    http://stackoverflow.com/questions/1802936/stop-all-active-ajax-requests-in-jquery
 */
jQuery.xhrPool = [];

/**
 * jQuery.xhrPool.abortAll
 * 
 * Retrieves all the outbound requests from the array (since the array is going
 * to be modified as requests are aborted), and then loops over each of them to
 * perform the abortion. Doing so will trigger the ajaxComplete event against
 * the document, which will remove the request from the pool-array.
 * 
 * @access public
 * @return void
 */
jQuery.xhrPool.abortAll = function() {
    var requests = [];
    for (var index in this) {
        if (isFinite(index) === true) {
            requests.push(this[index]);
        }
    }
    for (index in requests) {
        requests[index].abort();
    }
};

/**
 * jQuery.xhrPool.remove
 * 
 * Loops over the requests, removes it once (and if) found, and then breaks out
 * of the loop (since nothing else to do).
 * 
 * @access public
 * @param  Object jqXHR
 * @return void
 */
jQuery.xhrPool.remove = function(jqXHR) {
    for (var index in this) {
        if (this[index] === jqXHR) {
            jQuery.xhrPool.splice(index, 1);
            break;
        }
    }
};

/**
 * Below events are attached to the document rather than defined the ajaxSetup
 * to prevent possibly being overridden elsewhere (presumably by accident).
 */
$(document).ajaxSend(function(event, jqXHR, options) {
    jQuery.xhrPool.push(jqXHR);
});
$(document).ajaxComplete(function(event, jqXHR, options) {
    jQuery.xhrPool.remove(jqXHR);
});
onassar
sumber
2

Buat kumpulan semua permintaan ajax dan batalkan .....

var xhrQueue = []; 

$(document).ajaxSend(function(event,jqxhr,settings){
    xhrQueue.push(jqxhr); //alert(settings.url);
});

$(document).ajaxComplete(function(event,jqxhr,settings){
    var i;   
    if((i=$.inArray(jqxhr,xhrQueue)) > -1){
        xhrQueue.splice(i,1); //alert("C:"+settings.url);
    }
});

ajaxAbort = function (){  //alert("abortStart");
    var i=0;
    while(xhrQueue.length){ 
        xhrQueue[i++] .abort(); //alert(i+":"+xhrQueue[i++]);
    }
};
Zigri2612
sumber
1

Lebih baik menggunakan kode independen .....

var xhrQueue = []; 

$(document).ajaxSend(function(event,jqxhr,settings){
    xhrQueue.push(jqxhr); //alert(settings.url);
});

$(document).ajaxComplete(function(event,jqxhr,settings){
    var i;   
    if((i=$.inArray(jqxhr,xhrQueue)) > -1){
        xhrQueue.splice(i,1); //alert("C:"+settings.url);
    }
});

ajaxAbort = function (){  //alert("abortStart");
    var i=0;
    while(xhrQueue.length){ 
        xhrQueue[i++] .abort(); //alert(i+":"+xhrQueue[i++]);
    }
};
Zigri2612
sumber
0

Sama pentingnya: katakanlah Anda ingin keluar dan Anda membuat permintaan baru dengan timer: karena data sesi diperbarui dengan setiap bootstrap baru (mungkin Anda bisa mengatakan saya berbicara Drupal, tetapi ini bisa berupa situs yang menggunakan sesi). Saya harus memeriksa semua skrip saya dengan pencarian dan ganti, karena saya punya banyak hal yang berjalan dalam kasus yang berbeda: variabel global di atas:

var ajReq = [];
var canAj = true;
function abort_all(){
 for(x in ajReq){
    ajReq[x].abort();
    ajReq.splice(x, 1)
 }
 canAj = false;
}
function rmvReq(ranNum){
 var temp = [];
 var i = 0;
 for(x in ajReq){
    if(x == ranNum){
     ajReq[x].abort();
     ajReq.splice(x, 1);
    }
    i++;
 }
}
function randReqIndx(){
 if(!canAj){ return 0; }
 return Math.random()*1000;
}
function getReqIndx(){
 var ranNum;
 if(ajReq.length){
    while(!ranNum){
     ranNum = randReqIndx();
     for(x in ajReq){
    if(x===ranNum){
     ranNum = null;
    }
     }
    }
    return ranMum;
 }
 return randReqIndx();
}
$(document).ready(function(){
 $("a").each(function(){
    if($(this).attr('href').indexOf('/logout')!=-1){          
     $(this).click(function(){
    abort_all();                 
     });
    }
 })
});
// Then in all of my scripts I wrapped my ajax calls... If anyone has a suggestion for a 
    // global way to do this, please post
var reqIndx = getReqIndx();
if(reqIndx!=0){
ajReq[reqIndx] = $.post(ajax, { 'action': 'update_quantities', iids:iidstr, qtys:qtystr },  
function(data){
 //..do stuff
 rmvReq(reqIndx);
 },'json');
}
Kabar baik
sumber
0
var Request = {
    List: [],
    AbortAll: function () {
        var _self = this;
        $.each(_self.List, (i, v) => {
            v.abort();
        });
    }
}
var settings = {
    "url": "http://localhost",
    success: function (resp) {
        console.log(resp)
    }
}

Request.List.push($.ajax(settings));

setiap kali Anda ingin membatalkan semua permintaan ajax, Anda hanya perlu menghubungi saluran ini

Request.AbortAll()
Omid Matouri
sumber
-2

Ada solusi tiruan yang saya gunakan untuk membatalkan semua permintaan ajax. Solusi ini memuat ulang seluruh halaman. Solusi ini bagus jika Anda tidak suka menetapkan ID untuk setiap permintaan ajax, dan jika Anda membuat permintaan ajax di dalam untuk-loop. Ini akan memastikan semua permintaan ajax terbunuh.

location.reload();
ASAMMUR
sumber
-3

Berikut ini cara menghubungkan ini dengan klik apa pun (berguna jika halaman Anda melakukan banyak panggilan AJAX dan Anda mencoba menavigasi).

$ ->
    $.xhrPool = [];

$(document).ajaxSend (e, jqXHR, options) ->
    $.xhrPool.push(jqXHR)

$(document).ajaxComplete (e, jqXHR, options) ->
    $.xhrPool = $.grep($.xhrPool, (x) -> return x != jqXHR);

$(document).delegate 'a', 'click', ->
    while (request = $.xhrPool.pop())
      request.abort()
dB.
sumber