Как отменить / прервать запрос jQuery AJAX?

У меня есть запрос AJAX, который будет выполняться каждые 5 секунд. Но проблема перед запросом AJAX, если предыдущий запрос не завершен, я должен прервать этот запрос и сделать новый запрос.

мой код что-то вроде этого, как решить эту проблему?

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

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

8 ответов


метод 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);
);

Я знаю, что это может быть немного поздно, но я испытываю аналогичные проблемы, когда вызов метода abort действительно не прервал запрос. вместо этого браузер все еще ждал ответа, который он никогда не использует. этот код решил эту проблему.

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

почему вы должны прервать запрос?

Если каждый запрос занимает более пяти секунд, что будет?

вы не должны прерывать запрос, если параметр, передаваемый с запросом, не изменяется. например: - запрос предназначен для получения данных уведомления. В таких ситуациях хороший подход заключается в том, что новый запрос устанавливается только после завершения предыдущего запроса 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);

);

когда вы делаете запрос на сервер, сначала проверьте, не является ли прогресс нулевым (или получение этих данных). Если это выборка данных, прервите предыдущий запрос и инициируйте новый.

var progress = null

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

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

вы можете использовать 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);
    };
}

Так что вам просто нужно установить параметр режим to отмена когда вы делаете запрос ajax.

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


создайте функцию для вызова API. В рамках этой функции мы определяем request 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().


вы также должны проверить readyState 0. Потому что, когда вы используете xhr.abort () эта функция устанавливает readyState в 0 в этом объекте, и ваша проверка if всегда будет true - 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);
);