Come annullare / interrompere la richiesta jQuery AJAX?


244

Ho una richiesta AJAX che verrà effettuata ogni 5 secondi. Ma il problema è prima della richiesta AJAX se la richiesta precedente non è stata completata devo interrompere quella richiesta ed effettuare una nuova richiesta.

Il mio codice è qualcosa del genere, come risolvere questo problema?

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

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


5
La tua domanda afferma che la richiesta dovrebbe avvenire ogni 5 secondi, ma il codice utilizza 500 ms = 0,5 s.
geon,

Risposte:


355

Il metodo jquery ajax restituisce un oggetto XMLHttpRequest . È possibile utilizzare questo oggetto per annullare la richiesta.

XMLHttpRequest ha un metodo di interruzione , che annulla la richiesta, ma se la richiesta è già stata inviata al server, il server elaborerà la richiesta anche se interrompiamo la richiesta ma il client non attenderà / gestirà la risposta.

L'oggetto xhr contiene anche un readyState che contiene lo stato della richiesta (UNSENT-0, OPENED-1, HEADERS_RECEIVED-2, LOADING-3 e DONE-4). possiamo usarlo per verificare se la richiesta precedente è stata completata.

$(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 Le differenze sono la proprietà readystatesopra e readyStatesotto, il personaggio sè in maiuscolo in jQuery 1.5
Arun P Johny

Mi chiedevo cosa succederebbe se readyState fosse "LOADING-3" e ci interrompiamo? I dati vengono inviati al server e vengono elaborati o meno. Non lo sapremo ...: S
inf3rno,

7
A proposito, penso che il controllo readyState non sia necessario, poiché è rinviato e una volta risolto o rifiutato non eseguirà gli altri. Così if (xhr) xhr.abort();funzionano bene anche.
Ciantic,

2
W3 non ha mai usato non maiuscolo readystatenella sua documentazione. Era sempre in maiuscolo readyStatee jquery (prima o dopo la 1.5) corrispondeva correttamente alla specifica w3.
Arashsoft,

@ArunPJohny, puoi fare questa domanda stackoverflow.com/questions/49801146/…
Krishna Jonnalagadda

6

Quando si effettua una richiesta a un server, fare in modo che verifichi se un progresso non è nullo (o il recupero di tali dati) per primo. Se sta recuperando dati, annulla la richiesta precedente e avvia quella nuova.

var progress = null

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

5

So che potrebbe essere un po 'tardi, ma ho riscontrato problemi simili in cui la chiamata al metodo di interruzione non ha interrotto la richiesta. invece il browser stava ancora aspettando una risposta che non usa mai. questo codice ha risolto il problema.

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

1

Perché dovresti interrompere la richiesta?

Se ogni richiesta richiede più di cinque secondi, cosa accadrà?

Non interrompere la richiesta se il parametro che passa con la richiesta non cambia. es: - la richiesta è per il recupero dei dati di notifica. In tali situazioni, l'approccio gradevole è quello di impostare una nuova richiesta solo dopo aver completato la precedente richiesta 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
Questa è una cattiva idea. Quando si avvia una nuova chiamata, non si desidera che l'evento completo venga generato dalla chiamata precedente. Con questo approccio potresti ottenere risultati molto strani.
Webberig

1

Puoi usare jquery-validate.js. Di seguito è riportato lo snippet di codice di 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);
    };
}

In modo che sia sufficiente impostare la modalità parametro per interrompere quando si effettua una richiesta Ajax.

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


0

jQuery: usalo come punto di partenza, come ispirazione. L'ho risolto in questo modo: (questa non è una soluzione perfetta, interrompe solo l'ultima istanza ed è il codice 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

Crea una funzione per chiamare la tua API. All'interno di questa funzione definiamo richiesta callApiRequest = $.get(...- anche se questa è una definizione di una variabile, la richiesta viene chiamata immediatamente, ma ora abbiamo la richiesta definita come variabile. Prima di chiamare la richiesta, controlliamo se la nostra variabile è definita typeof(callApiRequest) != 'undefined'e anche se è in sospeso suggestCategoryRequest.state() == 'pending'- se entrambi sono veri, abbiamo .abort()la richiesta che impedirà l'esecuzione della callback riuscita.

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

    });
}

Il tuo server / API potrebbe non supportare l'interruzione della richiesta (cosa succede se l'API ha già eseguito un codice?), Ma il callback javascript non si attiverà. Ciò è utile, ad esempio quando si forniscono suggerimenti di input a un utente, come input di hashtag.

È possibile estendere ulteriormente questa funzione aggiungendo la definizione della richiamata dell'errore - cosa dovrebbe accadere se la richiesta fosse interrotta.

Un caso d'uso comune per questo frammento sarebbe un input di testo che viene generato keypressall'evento. È possibile utilizzare un timeout per impedire l'invio (di alcune) richieste che è necessario annullare .abort().


-7

Dovresti anche controllare readyState 0. Perché quando usi xhr.abort () questa funzione imposta readyState su 0 in questo oggetto e il tuo if check sarà sempre vero - 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
Hai copiato e incollato la risposta di Arun? Perché la probabilità che due blocchi di codice sia esattamente uguale, spaziatura e tutto il resto ...

@ user2700923 Il suo post non è esattamente lo stesso. Il suo punto è che dovremmo anche cercare readyState 0. Tuttavia questo sarebbe stato più appropriato come commento alla risposta di Arun.
Stefan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.