จะยกเลิก / ยกเลิกคำขอ jQuery AJAX ได้อย่างไร


244

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

รหัสของฉันเป็นแบบนี้จะแก้ไขปัญหานี้ได้อย่างไร

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

    var interval = setInterval(fn, 500);
);

10
ความเป็นไปได้ที่ซ้ำกันของคำขอฆ่า ajax โดยใช้ javascript โดยใช้ jquery
karim79

5
คำถามของคุณระบุคำขอควรเกิดขึ้นทุก 5 วินาที แต่รหัสใช้ 500 ms = 0.5 วินาที
geon

คำตอบ:


355

วิธีการ jquery ajax ส่งคืนวัตถุXMLHttpRequest คุณสามารถใช้วัตถุนี้เพื่อยกเลิกการร้องขอ

XMLHttpRequest มีการยกเลิกวิธีการที่จะยกเลิกคำขอ แต่ถ้าขอได้ถูกส่งไปยังเซิร์ฟเวอร์แล้วเซิร์ฟเวอร์จะดำเนินการตามคำขอแม้ว่าเราจะยกเลิกการร้องขอ แต่ลูกค้าจะไม่รอให้ / จัดการกับการตอบสนอง

วัตถุ xhr ยังมีreadyStateซึ่งมีสถานะของคำขอ (UNSENT-0, OPENED-1, HEADERS_RECEIVED-2, LOADING-3 และ DONE-4) เราสามารถใช้สิ่งนี้เพื่อตรวจสอบว่าคำขอก่อนหน้านี้เสร็จสมบูรณ์หรือไม่

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

60
@romkyns ความแตกต่างคือคุณสมบัติreadystateด้านบนและreadyStateด้านล่างอักขระsจะเป็นตัวพิมพ์ใหญ่ใน jQuery 1.5
Arun P Johny

ฉันสงสัยว่าจะเกิดอะไรขึ้นถ้า ReadyState คือ "LOADING-3" และเรายกเลิก? ข้อมูลถูกส่งไปยังเซิร์ฟเวอร์และมีการประมวลผลหรือไม่ เราจะไม่รู้ ... : S
inf3rno

7
Btw ฉันคิดว่าการตรวจสอบสถานะสำเร็จรูปนั้นไม่จำเป็นเนื่องจากจะถูกเลื่อนออกไปและเมื่อได้รับการแก้ไขหรือปฏิเสธจะไม่เรียกใช้การตรวจสอบอื่น ๆ ดังนั้นif (xhr) xhr.abort();จะทำงานได้ดีเช่นกัน
Ciantic

2
W3 ไม่เคยใช้ไม่ได้พิมพ์ใหญ่readystateในเอกสารของมัน มันเป็นตัวพิมพ์ใหญ่readyStateและ jquery (ก่อนหรือหลัง 1.5) เสมอตรงกับข้อกำหนด w3
Arashsoft

@ArunPJohny คุณช่วยกรุณาคำถามนี้stackoverflow.com/questions/49801146/…
กฤษณะ Jonnalagadda

6

เมื่อคุณทำการร้องขอไปยังเซิร์ฟเวอร์ให้ตรวจสอบเพื่อดูว่าความคืบหน้าไม่ใช่โมฆะ (หรือดึงข้อมูลนั้น) ก่อน หากกำลังดึงข้อมูลให้ยกเลิกการร้องขอก่อนหน้าและเริ่มต้นคำขอใหม่

var progress = null

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

5

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

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

1

ทำไมคุณควรยกเลิกการร้องขอ?

หากแต่ละคำขอใช้เวลามากกว่าห้าวินาทีจะเกิดอะไรขึ้น

คุณไม่ควรยกเลิกการร้องขอหากพารามิเตอร์ที่ผ่านไปพร้อมกับคำขอไม่เปลี่ยนแปลง เช่น: - คำขอสำหรับการดึงข้อมูลการแจ้งเตือน ในสถานการณ์เช่นนี้วิธีการที่ดีคือการตั้งค่าคำขอใหม่หลังจากทำคำขอ Ajax ก่อนหน้านี้ให้สมบูรณ์เท่านั้น

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

);

5
นี่เป็นความคิดที่ไม่ดี เมื่อเริ่มต้นการโทรใหม่คุณไม่ต้องการให้เหตุการณ์ทั้งหมดถูกเปิดใช้งานการโทรก่อนหน้า คุณอาจได้ผลลัพธ์ที่แปลกมากด้วยวิธีนี้
Webberig

1

คุณสามารถใช้ jquery-validate.js ต่อไปนี้เป็นข้อมูลโค้ดจาก 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);
    };
}

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

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


0

jQuery: ใช้สิ่งนี้เป็นจุดเริ่มต้น - เป็นแรงบันดาลใจ ฉันแก้ไขมันเช่นนี้: (นี่ไม่ใช่วิธีที่สมบูรณ์แบบเพียงแค่ยกเลิกอินสแตนซ์สุดท้ายและเป็นรหัส 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.

0

สร้างฟังก์ชั่นเพื่อเรียก API ของคุณ ภายในฟังก์ชั่นนี้เรากำหนดคำขอcallApiRequest = $.get(...- แม้ว่านี่จะเป็นคำจำกัดความของตัวแปรคำขอจะถูกเรียกทันที แต่ตอนนี้เรามีคำขอที่กำหนดเป็นตัวแปร ก่อนที่จะมีการเรียกคำขอเราจะตรวจสอบว่าตัวแปรของเราถูกกำหนดไว้หรือไม่typeof(callApiRequest) != 'undefined'และหากยังคงรอดำเนินการsuggestCategoryRequest.state() == 'pending'- หากทั้งคู่เป็นจริงเราจะ.abort()ทำการร้องขอเพื่อป้องกันไม่ให้การเรียกกลับสำเร็จ

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

    });
}

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

คุณสามารถขยายฟังก์ชั่นนี้ได้อีกโดยการเพิ่มคำจำกัดความของการเรียกกลับข้อผิดพลาด - จะเกิดอะไรขึ้นถ้าคำขอถูกยกเลิก

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


-7

คุณควรตรวจสอบ readyState 0 เพราะเมื่อคุณใช้ xhr.abort () ฟังก์ชั่นนี้ตั้งค่า readyState เป็น 0 ในวัตถุนี้และถ้าการตรวจสอบของคุณจะเป็นจริงเสมอ - 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);
); 

2
คุณคัดลอกและวางคำตอบของอรุณหรือไม่ เนื่องจากความเป็นไปได้ของการบล็อกโค้ดสองแบบที่เหมือนกันคือการเว้นวรรคและ ...

@ user2700923 โพสต์ของเขาไม่เหมือนกันทุกประการ ประเด็นของเขาคือเราควรตรวจสอบให้พร้อมสำหรับสถานะ 0 อย่างไรก็ตามนี่น่าจะเหมาะสมกว่าสำหรับความเห็นต่อคำตอบของอรุณ
สเตฟาน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.