Comment annuler / abandonner la requête jQuery AJAX?

244

J'ai une demande AJAX qui sera faite toutes les 5 secondes. Mais le problème est avant la demande AJAX si la demande précédente n'est pas terminée, je dois abandonner cette demande et faire une nouvelle demande.

Mon code est quelque chose comme ça, comment résoudre ce problème?

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

    var interval = setInterval(fn, 500);
);
user556673
la source
5
Votre question indique que la demande doit se produire toutes les 5 secondes, mais le code utilise 500 ms = 0,5 s.
geon

Réponses:

355

La méthode jquery ajax renvoie un XMLHttpRequest objet . Vous pouvez utiliser cet objet pour annuler la demande.

XMLHttpRequest a une méthode d' abandon , qui annule la demande, mais si la demande a déjà été envoyée au serveur, le serveur traitera la demande même si nous abandonnons la demande, mais le client n'attendra pas / ne gérera pas la réponse.

L'objet xhr contient également un readyState qui contient l'état de la demande (UNSENT-0, OPENED-1, HEADERS_RECEIVED-2, LOADING-3 et DONE-4). nous pouvons l'utiliser pour vérifier si la demande précédente a été traitée.

$(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);
);
Arun P Johny
la source
60
@romkyns Les différences sont la propriété readystateci-dessus et readyStateci - dessous, le caractère sest mis en majuscule dans jQuery 1.5
Arun P Johny
Je me demandais ce qui se passe si le readyState est "LOADING-3" et nous avortons? Les données sont envoyées au serveur et sont traitées ou non. On ne sait pas ...: S
inf3rno
7
Btw, je pense que le contrôle readyState n'est pas nécessaire, car il est différé et une fois qu'il est résolu ou rejeté, il ne fonctionnera pas les autres. Cela if (xhr) xhr.abort();fonctionnera très bien aussi.
Ciantic
2
W3 n'a jamais utilisé non capitalisé readystatedans sa documentation. Il a toujours été mis en majuscule readyStateet jquery (avant ou après 1.5) correspond correctement à la spécification w3.
Arashsoft
@ArunPJohny, pouvez-vous pls cette question stackoverflow.com/questions/49801146/…
Krishna Jonnalagadda
6

Lorsque vous faites une demande à un serveur, faites-le vérifier pour voir si une progression n'est pas nulle (ou récupérer ces données) en premier. S'il récupère des données, abandonnez la demande précédente et lancez la nouvelle.

var progress = null

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

Je sais que cela pourrait être un peu en retard, mais je rencontre des problèmes similaires où l'appel de la méthode d'abandon n'a pas vraiment avorté la demande. au lieu de cela, le navigateur attendait toujours une réponse qu'il n'utilise jamais. ce code a résolu ce problème.

 try {
        xhr.onreadystatechange = null;
        xhr.abort();
} catch (e) {}
Lyon
la source
1

Pourquoi devriez-vous abandonner la demande?

Si chaque demande dure plus de cinq secondes, que se passera-t-il?

Vous ne devez pas abandonner la demande si le paramètre transmis avec la demande ne change pas. par exemple: - la demande concerne la récupération des données de notification. Dans de telles situations, l'approche intéressante consiste à définir une nouvelle demande uniquement après avoir terminé la demande Ajax précédente.

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

);
Habeeb Perwad
la source
5
C'est une mauvaise idée. Lorsque vous commencez un nouvel appel, vous ne voulez pas que l'événement complet soit déclenché de l'appel précédent. Vous pourriez obtenir des résultats très étranges avec cette approche.
Webberig
1

Vous pouvez utiliser jquery-validate.js. Voici l'extrait de code de 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);
    };
}

Pour que vous n'ayez à régler le mode des paramètres que pour annuler lorsque vous effectuez une demande ajax.

Réf: https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.14.0/jquery.validate.js

zawhtut
la source
0

jQuery: Utilisez-le comme point de départ - comme source d'inspiration. Je l'ai résolu comme ceci: (ce n'est pas une solution parfaite, il abandonne simplement la dernière instance et est du code 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.
BananaAcid
la source
0

Créez une fonction pour appeler votre API. Dans cette fonction, nous définissons la demande callApiRequest = $.get(...- même s'il s'agit d'une définition d'une variable, la demande est appelée immédiatement, mais nous avons maintenant la demande définie comme une variable. Avant d'appeler la demande, nous vérifions si notre variable est définie typeof(callApiRequest) != 'undefined'et aussi si elle est en attente suggestCategoryRequest.state() == 'pending'- si les deux sont vraies, nous .abort()la demande qui empêchera le rappel de succès de s'exécuter.

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

    });
}

Votre serveur / API peut ne pas prendre en charge l'abandon de la demande (que faire si l'API a déjà exécuté du code?), Mais le rappel javascript ne se déclenchera pas. Ceci est utile lorsque, par exemple, vous fournissez des suggestions de saisie à un utilisateur, telles que la saisie de hashtags.

Vous pouvez étendre cette fonction en ajoutant la définition du rappel d'erreur - ce qui devrait se produire si la demande a été abandonnée.

Le cas d'utilisation courant de cet extrait serait une entrée de texte qui se déclenche lors d'un keypressévénement. Vous pouvez utiliser un délai d'expiration pour empêcher l'envoi (de certaines) demandes que vous devrez annuler .abort().

mate.gwozdz
la source
-7

Vous devez également rechercher readyState 0. Parce que lorsque vous utilisez xhr.abort (), cette fonction définit readyState à 0 dans cet objet, et votre vérification if sera toujours vraie - 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);
); 
programmeur
la source
2
Avez-vous copié et collé la réponse d'Arun? Parce que la probabilité que deux blocs de code comme celui-ci soient exactement les mêmes, l'espacement et tout ...
@ user2700923 Son message n'est pas exactement le même. Son point est que nous devrions également vérifier pour readyState 0. Cependant, cela aurait été plus approprié comme commentaire à la réponse d'Arun.
Stefan