如何取消/中止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 ms = 0.5 s。
geon

Answers:


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

7
顺便说一句,我认为readyState检查是不必要的,因为它被推迟了,一旦解决或被拒绝,它将不再运行其他检查。因此if (xhr) xhr.abort();也可以正常工作。
Ciantic

2
W3从未使用过但未readystate在其文档中大写。始终将其大写,readyState并且jquery(在1.5之前或之后)正确匹配w3规范。
Arashsoft

@ArunPJohny,你能不能请这个问题stackoverflow.com/questions/49801146/...
克里希纳Jonnalagadda

5

我知道这可能会晚一点,但是我遇到类似的问题,其中调用中止方法并没有真正中止请求。相反,浏览器仍在等待它从未使用过的响应。此代码解决了该问题。

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

5

向服务器发出请求时,请先检查进度是否不为空(或获取该数据)。如果正在获取数据,请中止上一个请求并启动新请求。

var progress = null

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

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
这是一个坏主意。发起新呼叫时,您不希望触发上一个呼叫的complete事件。使用这种方法可能会得到非常奇怪的结果。
Webberig 2014年

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'-如果两个都为true,.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,并且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);
); 

2
您是否复制并粘贴了Arun的答案?因为像这样的两个代码块的可能性完全相同,所以间距和所有...

@ user2700923他的帖子不完全相同。他的观点是,我们还应该检查readyState0。但是,作为对Arun答案的注释,这会更合适。
Stefan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.