Як скасувати / скасувати запит 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);
);


5
У вашому запитанні зазначено, що запит має відбуватися кожні 5 секунд, але код використовує 500 мс = 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 - "ЗАВАНТАЖЕННЯ-3", і ми перериваємо? Дані надсилаються на сервер, вони обробляються чи ні. Ми не будемо знати ...: S
inf3rno

7
До речі, я вважаю, що перевірка ReadyState є непотрібною, оскільки вона відкладена і після її вирішення або відхилення не запустить інші. Так if (xhr) xhr.abort();буде теж добре працювати.
Сіантік

2
W3 ніколи не використовувався, не використовуючи великі літери readystateу своїй документації. Він завжди з великої літери readyStateта jquery (до або після 1,5) правильно відповідають специфікації w3.
Arashsoft

@ArunPJohny, може ви Pls це питання 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
Це погана ідея. Під час запуску нового дзвінка ви не хочете, щоб завершення події було завершено з попереднього дзвінка. Ви можете отримати дуже дивні результати при такому підході.
Вебберіг

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.

Посилання: 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. Однак це було б більш доречно як коментар до відповіді Аруна.
Стефан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.