Dừng tất cả các yêu cầu ajax đang hoạt động trong jQuery


216

Tôi có một vấn đề, khi gửi một biểu mẫu tất cả yêu cầu ajax hoạt động đều thất bại và điều đó gây ra sự kiện lỗi.

Làm cách nào để dừng tất cả các yêu cầu ajax đang hoạt động trong jQuery mà không gặp sự cố lỗi nào?

Câu trả lời:


273

Mỗi khi bạn tạo một yêu cầu ajax, bạn có thể sử dụng một biến để lưu trữ nó:

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

Sau đó, bạn có thể hủy bỏ yêu cầu:

request.abort();

Bạn có thể sử dụng một mảng theo dõi tất cả các yêu cầu ajax đang chờ xử lý và hủy bỏ chúng nếu cần thiết.


THX, tôi đã thêm một FLAG vì tôi đã sử dụng nhiều yêu cầu cùng một lúc
jcho360

đây là ví dụ làm việc đơn giản: stackoverflow.com/a/42312101/3818394
Dharmesh patel

Tôi có chức năng gọi ajax làm thế nào tôi có thể hủy bỏ nó?
Kalariya_M

Biến phải được khai báo toàn cục để truy cập nó từ một chức năng khác khi cuộc gọi ajax đang diễn ra. ví dụ: một quá trình tải lên nhiều tập tin.
Clain Dsilva

180

Đoạn mã sau cho phép bạn duy trì một danh sách ( nhóm ) yêu cầu và hủy bỏ tất cả chúng nếu cần. Tốt nhất để đặt vào <HEAD>html của bạn, trước khi bất kỳ cuộc gọi AJAX nào khác được thực hiện.

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

2
@mkm bồ - về việc vô sinh hóa trong IE8 tôi dường như nhận được Object doesn't support property or method 'indexOf'? Tôi nghi ngờ nó có thể là stackoverflow.com/a/2608601/181971 hoặc có thể chỉ đơn giản là trao đổi thành stackoverflow.com/a/2608618/181971 ?
Tim

3
@grr là đúng, xem câu trả lời của anh ấy và kiểm tra tài liệu cho ajaxSetup .
kzfabi

@Tim - như Steven đề xuất, thay vì var index = $ .xhrPool.indexOf (jqXHR); sử dụng: var index = $ .inArray (jqXHR, $ .xhrPool);
Christopher

1
@mkm bồ: Nó cho thấy TypeError: jqXHR.abort không phải là một chức năng cho tôi. :(
Shesha

Có một lỗi logic nhỏ trong phương thức abort ALL, được sửa ở đây trong câu trả lời này stackoverflow.com/a/45500874/1041341
Sarin JS

122

Sử dụng ajaxSetup là không chính xác , như được lưu ý trên trang tài liệu của nó. Nó chỉ thiết lập mặc định và nếu một số yêu cầu ghi đè lên chúng sẽ có một mớ hỗn độn.

Tôi đến bữa tiệc muộn, nhưng chỉ để tham khảo trong tương lai nếu ai đó đang tìm giải pháp cho cùng một vấn đề, đây là cách của tôi, lấy cảm hứng và phần lớn giống với các câu trả lời trước, nhưng đầy đủ hơn

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

Làm thế nào để gọi phương thức abort () từ các hàm khác?
Stan James

hủy bỏ là một chức năng, không phải là một phương pháp. bạn gọi nó từ trong cùng một đóng gói thông thường, nếu bạn cần sử dụng nó bên ngoài đóng gói, bạn có thể xóa "var" trước tên hàm và nó sẽ trở thành một funciton có sẵn trên toàn cầu
Trey

Xin chào, ai đó có thể giải thích khi r sẽ không được xác định?
Varun

36

Đây là những gì tôi đang sử dụng để thực hiện điều đó.

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

Lưu ý: _.each của underscore.js có mặt, nhưng rõ ràng là không cần thiết. Tôi chỉ lười biếng và tôi không muốn đổi nó thành $ .each (). 8P


2
Tôi đã có một giải pháp sửa đổi một chút mà hoạt động tuyệt vời mà tôi sắp đăng.
mkmah

7
Bộ nhớ này bị rò rỉ. aboutAllnên loại bỏ các yếu tố từ mảng. Ngoài ra, khi yêu cầu kết thúc, nó sẽ tự xóa khỏi danh sách.
Behrang Saeedzadeh

5
@BehrangSaeedzadeh Bạn cũng nên đăng một phiên bản cải tiến.
mattsven

19

Cung cấp cho mỗi xhr yêu cầu một id duy nhất và lưu trữ tham chiếu đối tượng trong một đối tượng trước khi gửi. Xóa tham chiếu sau khi yêu cầu xhr hoàn thành.

Để hủy tất cả yêu cầu bất cứ lúc nào:

$.ajaxQ.abortAll();

Trả về id duy nhất của yêu cầu bị hủy. Chỉ dành cho mục đích thử nghiệm.

Chức năng làm việc:

$.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;
    }
  };

})();

Trả về một đối tượng với chức năng duy nhất có thể được sử dụng để thêm nhiều chức năng hơn khi được yêu cầu.


17

Tôi thấy nó quá dễ dàng cho nhiều yêu cầu.

bước 1: xác định một biến ở đầu trang:

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

step2: đặt beforeSend trong tất cả các yêu cầu ajax:

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

Bước 3: sử dụng bất cứ nơi nào bạn cần:

   $.each(xhrPool, function(idx, jqXHR) {
          jqXHR.abort();
    });

Bộ nhớ này bị rò rỉ, giống như stackoverflow.com/a/6618288/1772379 , và vì những lý do chính xác tương tự.
Ben Johnson

Cách thực sự khủng khiếp để viết JavaScript.
Ozil

1
cuối cùng bạn có thể xóa / làm trống mảng xhrPool
không gian trái đất

6

Tôi đã mở rộng câu trả lời của mkm bồ và SpYk3HH ở trên để xhrPool.abort ALL có thể hủy bỏ tất cả các yêu cầu đang chờ xử lý của một url đã cho :

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

Việc sử dụng là như nhau ngoại trừ việc abort ALL hiện có thể tùy ý chấp nhận một url làm tham số và sẽ chỉ hủy các cuộc gọi đang chờ xử lý đến url đó


5

Tôi đã có một số vấn đề với mã của Andy, nhưng nó đã cho tôi một số ý tưởng tuyệt vời. Vấn đề đầu tiên là chúng ta nên bật ra bất kỳ đối tượng jqXHR nào hoàn thành thành công. Tôi cũng đã phải sửa đổi chức năng abort ALL. Đây là mã làm việc cuối cùng của tôi:

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

Tôi không thích cách làm ajaxComplete (). Không có vấn đề làm thế nào tôi cố gắng cấu hình .ajaxSetup nó không hoạt động.


7
Tôi nghĩ rằng bạn có thể đang gọi pop theo yêu cầu sai nếu họ không hoàn thành theo một thứ tự cụ thể?
jjmontes

1
Có, bạn muốn làm lát thay vì pop. Tôi đã có một giải pháp sửa đổi một chút mà tôi sắp đăng.
mkmah

4

Tôi đã cập nhật mã để làm cho nó hoạt động với tôi

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

4

Ném mũ của tôi vào. Cung cấp abortremovephương pháp chống lại xhrPoolmảng, và không có vấn đề với các phần ajaxSetupghi đè.

/**
 * Ajax Request Pool
 * 
 * @author Oliver Nassar <onassar@gmail.com>
 * @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);
});

2

Tạo một nhóm tất cả các yêu cầu ajax và hủy bỏ chúng .....

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

1

Tốt hơn để sử dụng mã độc lập .....

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

0

Cũng quan trọng không kém: giả sử bạn muốn đăng xuất và bạn đang tạo các yêu cầu mới bằng bộ hẹn giờ: vì dữ liệu phiên được đổi mới với mỗi bootstrap mới (có thể bạn có thể nói tôi đang nói về Drupal, nhưng đây có thể là bất kỳ trang web nào sử dụng phiên) .. Tôi đã phải xem qua tất cả các tập lệnh của mình bằng một tìm kiếm và thay thế, vì tôi có rất nhiều thứ đang chạy trong các trường hợp khác nhau: các biến toàn cục ở đầu:

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

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

Bất cứ khi nào bạn muốn hủy bỏ tất cả các yêu cầu ajax, bạn chỉ cần gọi đường dây này

Request.AbortAll()

-2

Có một giải pháp giả tôi sử dụng nó để hủy bỏ tất cả các yêu cầu ajax. Giải pháp này được tải lại toàn bộ trang. Giải pháp này rất tốt nếu bạn không muốn gán ID cho từng yêu cầu ajax và nếu bạn thực hiện các yêu cầu ajax bên trong vòng lặp for. Điều này sẽ đảm bảo tất cả các yêu cầu ajax bị giết.

location.reload();

-3

Đây là cách kết nối điều này với bất kỳ nhấp chuột nào (hữu ích nếu trang của bạn đang thực hiện nhiều cuộc gọi AJAX và bạn đang cố điều hướng đi).

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