หยุดการร้องขอ ajax ที่แอ็คทีฟทั้งหมดใน jQuery


216

ฉันมีปัญหาเมื่อส่งแบบฟอร์มคำขอ ajax ทั้งหมดที่ใช้งานล้มเหลวและทำให้เกิดข้อผิดพลาด

วิธีหยุดคำขอ ajax ที่แอ็คทีฟทั้งหมดใน jQuery โดยไม่มีเหตุการณ์ข้อผิดพลาดทริกเกอร์

คำตอบ:


273

ทุกครั้งที่คุณสร้างคำขอ ajax คุณสามารถใช้ตัวแปรเพื่อจัดเก็บ:

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

จากนั้นคุณสามารถยกเลิกการร้องขอ:

request.abort();

คุณสามารถใช้อาร์เรย์ติดตามคำขออาแจ็กซ์ที่ค้างอยู่ทั้งหมดและยกเลิกพวกเขาหากจำเป็น


ขอบคุณฉันเพิ่มธงเพราะฉันใช้คำขอหลายรายการในเวลาเดียวกัน
jcho360

นี่เป็นตัวอย่างการทำงานง่าย ๆ : stackoverflow.com/a/42312101/3818394
Dharmesh patel

ฉันมีฟังก์ชั่น ajax call ฉันจะยกเลิกได้อย่างไร?
Kalariya_M

ตัวแปรจะต้องมีการประกาศทั่วโลกเพื่อเข้าถึงได้จากฟังก์ชั่นอื่นเมื่อมีการโทร ajax ตัวอย่าง: กระบวนการอัปโหลดหลายไฟล์
Clain Dsilva

180

ตัวอย่างต่อไปนี้ช่วยให้คุณรักษารายการ ( พูล ) ของคำขอและยกเลิกทั้งหมดหากจำเป็น ที่ดีที่สุดที่จะอยู่ใน<HEAD>html ของคุณก่อนที่จะมีการโทร AJAX อื่น ๆ

<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
@mkmurray - การทำให้มีพลังใน IE8 ฉันดูเหมือนจะได้รับObject doesn't support property or method 'indexOf'? ฉันสงสัยว่ามันอาจจะstackoverflow.com/a/2608601/181971หรืออาจจะเพียงแค่การแลกเปลี่ยนเพื่อstackoverflow.com/a/2608618/181971 ?
ทิม

3
@grr ที่เหมาะสมให้ดูคำตอบของเขาและตรวจสอบเอกสารสำหรับajaxSetup
kzfabi

@Tim - ตามที่ Steven แนะนำแทนที่จะเป็น var index = $ .xhrPool.indexOf (jqXHR); ใช้: var index = $ .inArray (jqXHR, $ .xhrPool);
คริสโตเฟอร์

1
@mkmurray: มันแสดงให้เห็น TypeError: jqXHR.abort ไม่ใช่ฟังก์ชั่นสำหรับฉัน :(
Shesha

มีข้อผิดพลาดทางตรรกะเล็กน้อยในวิธีการ abortAll ซึ่งได้รับการแก้ไขที่นี่ในคำตอบนี้stackoverflow.com/a/45500874/1041341
Sarin JS

122

การใช้ajaxSetup ไม่ถูกต้องดังที่บันทึกไว้ในหน้าเอกสาร มันตั้งค่าเริ่มต้นเท่านั้นและหากคำขอบางอย่างแทนที่พวกเขาจะมีระเบียบ

ฉันไปงานปาร์ตี้ช้า แต่สำหรับการอ้างอิงในอนาคตหากใครบางคนกำลังมองหาวิธีการแก้ปัญหาเดียวกันนี่คือฉันไปที่มันแรงบันดาลใจจากและส่วนใหญ่เหมือนคำตอบก่อนหน้า แต่สมบูรณ์มากขึ้น

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

หนึ่งเรียกวิธีการยกเลิก () วิธีการจากฟังก์ชั่นอื่น ๆ ?
Stan James

การยกเลิกเป็นฟังก์ชั่นไม่ใช่วิธีการ คุณเรียกมันจากภายใน encapsulation เดียวกันโดยปกติถ้าคุณจำเป็นต้องใช้มันนอก encapsulation คุณสามารถลบ "var" ก่อนชื่อฟังก์ชันและมันจะกลายเป็น funciton ทั่วโลกที่มีอยู่
Trey

สวัสดีมีคนอธิบายได้เมื่อ r จะไม่ได้กำหนด?
Varun

36

นี่คือสิ่งที่ฉันกำลังใช้เพื่อให้บรรลุ

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

หมายเหตุ: _.each ของ underscore.js มีอยู่ แต่เห็นได้ชัดว่าไม่จำเป็น ฉันขี้เกียจและฉันไม่ต้องการเปลี่ยนเป็น $ .each () 8P


2
ฉันมีวิธีแก้ไขเล็กน้อยที่ใช้งานได้ดีที่ฉันเพิ่งโพสต์
mkmurray

7
หน่วยความจำรั่ว aboutAllควรลบองค์ประกอบออกจากอาร์เรย์ เมื่อคำขอเสร็จสิ้นก็ควรลบตัวเองออกจากรายการ
Behrang Saeedzadeh

5
@BehrangSaeedzadeh คุณควรโพสต์เวอร์ชันที่ปรับปรุงแล้วด้วย
mattsven

19

ให้แต่ละ xhr ร้องขอ id ที่ไม่ซ้ำกันและเก็บการอ้างอิงวัตถุในวัตถุก่อนที่จะส่ง ลบการอ้างอิงหลังจากการร้องขอ xhr เสร็จสมบูรณ์

หากต้องการยกเลิกการร้องขอทั้งหมดได้ตลอดเวลา:

$.ajaxQ.abortAll();

ส่งคืนรหัสประจำตัวที่ไม่ซ้ำกันของคำขอที่ถูกยกเลิก เพื่อการทดสอบเท่านั้น

ฟังก์ชั่นการทำงาน:

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

})();

ส่งคืนวัตถุที่มีฟังก์ชั่นเดียวซึ่งสามารถใช้เพื่อเพิ่มฟังก์ชั่นมากขึ้นเมื่อจำเป็น


17

ฉันพบว่ามันง่ายเกินไปสำหรับหลายคำขอ

ขั้นที่ 1:กำหนดตัวแปรที่ด้านบนของหน้า:

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

ขั้นที่ 2:ตั้งไว้ก่อนส่งในคำขอ ajax ทั้งหมด:

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

ขั้นที่ 3:ใช้ตามที่คุณต้องการ:

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

หน่วยความจำรั่วนี้เช่นเดียวกับstackoverflow.com/a/6618288/1772379ทำและด้วยเหตุผลเดียวกันอย่างแม่นยำ
เบ็นจอห์นสัน

วิธีเขียน JavaScript ที่น่ากลัวจริงๆ
Ozil

1
อาจเป็นตอนท้ายคุณสามารถล้าง / ล้างอาเรย์ xhrPool
space space

6

ฉันขยาย mkmurray และคำตอบ SpYk3HH ด้านบนเพื่อให้ xhrPool.abortAll สามารถยกเลิกการร้องขอที่รอดำเนินการทั้งหมดของ URL ที่กำหนด :

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

การใช้งานเหมือนกันยกเว้นว่า abortAll สามารถเลือกที่จะยอมรับ URL เป็นพารามิเตอร์และจะยกเลิกเฉพาะการโทรไปยัง URL นั้น


5

ฉันมีปัญหากับโค้ดของ andy แต่มันให้ความคิดที่ดีกับฉัน ปัญหาแรกคือเราควรจะปิดวัตถุ jqXHR ใด ๆ ที่เสร็จสมบูรณ์ ฉันต้องแก้ไขฟังก์ชัน abortAll ด้วย นี่คือรหัสการทำงานสุดท้ายของฉัน:

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

ฉันไม่ชอบวิธี ajaxComplete () ในการทำสิ่งต่าง ๆ ไม่ว่าฉันจะพยายามกำหนดค่า. AjaxSetup มันไม่ทำงาน


7
ฉันคิดว่าคุณอาจจะเรียกป๊อปตามคำขอที่ไม่ถูกต้องหากพวกเขาไม่ได้ดำเนินการตามลำดับที่เฉพาะเจาะจงหรือไม่
jjmontes

1
ใช่คุณต้องการที่จะฝานแทนป๊อป ฉันมีวิธีแก้ไขเล็กน้อยที่ฉันจะโพสต์
mkmurray

4

ฉันได้อัปเดตรหัสเพื่อให้ใช้งานได้สำหรับฉัน

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

โยนหมวกของฉันเข้าข้อเสนอabortและremoveวิธีการต่อต้านxhrPoolแถวลำดับและไม่น่าจะมีปัญหากับการajaxSetupแทนที่

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

สร้างกลุ่มคำขออาแจ็กซ์ทั้งหมดและยกเลิก .....

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

ดีกว่าที่จะใช้รหัสอิสระ .....

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

มีความสำคัญพอเพียง: บอกว่าคุณต้องการออกจากระบบและคุณกำลังสร้างคำขอใหม่ด้วยตัวจับเวลา: เนื่องจากข้อมูลเซสชันได้รับการต่ออายุด้วย bootstrap ใหม่แต่ละอัน (บางทีคุณอาจบอกได้ว่าฉันกำลังพูดถึง Drupal แต่นี่อาจเป็นเว็บไซต์ที่ใช้เซสชัน) ฉันต้องผ่านสคริปต์ทั้งหมดของฉันด้วยการค้นหาและแทนที่ทำให้ฉันมีสิ่งต่าง ๆ มากมายที่ทำงานในกรณีที่แตกต่างกัน: ตัวแปรทั่วโลกที่ด้านบน:

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

เมื่อใดก็ตามที่คุณต้องการยกเลิกคำขอ ajax ทั้งหมดคุณเพียงแค่เรียกสายนี้

Request.AbortAll()

-2

มีวิธีแก้ปัญหาหลอกตาฉันใช้เพื่อยกเลิกการร้องขอ ajax ทั้งหมด โซลูชันนี้โหลดซ้ำทั้งหน้า วิธีนี้เป็นวิธีที่ดีถ้าคุณไม่ต้องการกำหนด ID ให้กับคำขอ ajax แต่ละคำขอและถ้าคุณทำการร้องขอ ajax ภายใน for-loop นี่จะทำให้แน่ใจว่าคำขอ ajax ทั้งหมดถูกฆ่า

location.reload();

-3

ต่อไปนี้เป็นวิธีการเชื่อมโยงสิ่งนี้เข้ากับการคลิกใด ๆ (มีประโยชน์หากหน้าของคุณกำลังโทร AJAX จำนวนมากและคุณพยายามนำทางไป)

$ ->
    $.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()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.