2017-06-15 1 views
2

J'ai construit une application javascript qui a un graphique avec quelques filtres déroulants que les utilisateurs peuvent changer. Les listes déroulantes ont toutes des écouteurs d'événements qui soumettent une requête de serveur pour obtenir les données (via un appel jquery ajax), puis ils représentent graphiquement les données. Le problème est que l'utilisateur utilise le clavier pour parcourir rapidement de nombreux éléments différents de la liste déroulante. L'appel du serveur prend environ une seconde, donc s'ils défilent rapidement par 20, cela peut entraîner une accumulation. 20 demandes différentes au serveur sont créées, et il n'y a même pas de garantie que le dernier morceau de code à exécuter sur le serveur demande le succès sera le filtre le plus courant.Tuer des appels ajax si un nouveau est lancé

Donc, ma question est de savoir quelle est la meilleure façon quand un filtre est modifié pour tuer tous les autres processus asynchrones? Voici le code correspondant:

$("#filter").change(function(d) { 
    getData(); 
} //end of if 
}); 

function getData() { 
    ... 
    $.ajax({ 
    url: myUrl 
    type: "GET", 
    dataType: "json", 
    success: function(d) { 
     [do some stuff] 
     } //end of success function 
    }); //end of ajax 
} //end of getData 
+0

Vous avez une accolade supplémentaire dans cette première fonction, il dit qu'il ferme un 'if'. – AtheistP3ace

+0

Vous devez attendre que la requête en cours d'exécution soit terminée avant d'en envoyer une nouvelle (et ignorer certaines requêtes qui pourraient se produire pendant que la requête en cours est en cours d'exécution). Même si vous utilisiez la fonctionnalité 'abort' de' XMLHttpRequest2', cela pourrait entraîner une charge de serveur trop élevée. –

+0

Copie possible de [Annuler l'appel AJAX précédent lorsqu'un nouveau est fait?] (Https://stackoverflow.com/questions/9285271/abort-previous-ajax-call-when-a-new-one-made) –

Répondre

1

Enregistrer tous les appels Ajax que vous souhaitez abandonner dans une variable, vous pouvez annuler le dernier appel.

Ceci est un très courant pratique quand un appel ajax peut arriver plusieurs fois, avant ceux avant qu'il ait eu une chance de finir.

function getData(){ 
    $filter.data('REQ') && $filter.data('REQ').abort(); // abort the last request before creating a new one 

    return $.ajax({ 
     url:myUrl 
     type:"GET", 
     dataType:"json", 
     success:function(d){ 
      [do some stuff] 
     } 
    }) 
} 

var $filter = $("#filter"); 

$filter.on('change', function(d) { 
    $filter.data('REQ', getData()) 
}); 

Of-Bien sûr, cela est une manière très simplifiée de code et vous devez ré-écrire ceci d'une manière plus structurée, mais il vous donne une idée de la façon de mettre en cache la dernière demande de paiement ajax et vous avez la pouvoir l'annuler avant d'envoyer un nouvel appel.


D'ailleurs, votre titre n'a rien à voir avec la question. Vous demandez comment gérer une séquence d'appels ajax mais en posant des questions sur des événements. cette question n'a rien à voir avec les événements, vous devez donc modifier le titre pour l'adapter au problème.


Mise à jour sur ce que @ t.niese avait dit dans les commentaires:

étranglés demandes du côté client est également un bon jeu à faire, car le serveur ne peut pas vraiment savoir si le client a avorté la demande ou non, et s'il s'agit d'une requête exigeant des ressources, elle doit être limitée. MAIS, je suggérerais de limiter les demandes côté serveur et non côté client, si possible, car la limitation côté client pourrait être contournée et ne serait pas fiable à 100%, et cela «coûterait» le même montant de temps pour le faire du côté serveur.

Can a http server detect that a client has cancelled their request?

+1

J'ai modifié le code un peu, juste stocké la requête ajax à une variable avec la portée globale et appelé abort sur cette variable au début de getData, mais l'approche a fonctionné parfaitement grâce. – zachvac

+0

heureux que cela fonctionne et je suis heureux que vous avez appris quelque chose de nouveau. – vsync

+0

Il est à noter que 'abort' n'arrêtera la requête que du côté client, mais une fois qu'il aura atteint le serveur, le serveur pourra toujours avoir besoin de faire tout le traitement de la requête, même s'il a été abandonné. Cela n'a donc peut-être pas d'effet sur la charge du serveur, et si cela se traduit par un goulot d'étranglement, alors «abort» ne vous aidera pas, et le nombre de requêtes émises devrait être limité. @zachvac –

-1

Je laisserais tomber toutes les tentatives lancer une nouvelle demande d'appel getData alors qu'une requête en cours est en cours d'exécution, et d'envoyer uniquement la dernière tentative getData dès que la demande en cours est terminée. Cela garantira que le chargement du serveur ne deviendra pas inutilement élevé, car une seule requête sera exécutée.

var currentRequest; 
var resubmitRequest; 

function getData() { 

    // only start a new request id no current request is running 
    if (!currentRequest) { 
    resubmitRequest = false; 
    currentRequest = Promise.resolve($.ajax({ 
     url: myUrl 
     type: "GET", 
     dataType: "json" 
    })); //end of ajax 

    currentRequest 
     .then((d) => { 
     [do some stuff] 
     }) 
     .finally(() => { 
     // if the current request finished and another attempt to request data 
     // happened while this request was running then call getData again 
     if (resubmitRequest) { 
      getData() 
     } 
     }) 

    } else { 
    // store the information that the data has to be requested 
    // another time after the currently running request finished 
    resubmitRequest = true; 
    } 

    return currentRequest; 
} //end of getData 
-1

vous pouvez simplement le mettre en pause par exemple à 500mil secondes puis exécuter la dernière modification et faire cet appel ajax.

$("#filter").change(function(d) { 
    if($.active > 0) return false; 
    // do not run new ajax if last one is not finished 
    clearTimeout(window.timer); 
    // if new 'change' evt is raised in less then 500 mils 
    // then clear it and run 'last' one 
    window.timer = setTimeout(function(){ 
    getData(); 
    }, 500); 
}); 

en cas si l'utilisateur il change tout en faisant ajax, return false it :)

-1

Avec peu d'effort, vous pouvez coder votre propre handler pour ces cas:

function handler(ms, fn) { 
    var eventId; 
    return function() { 
     // if there is an event programmed, kill it 
     clearTimeout(eventId); 
     // and program the new one (replace the event) 
     eventId = setTimeout(fn); 
     // if passed the time no event was programmed, setTimeout is going to execute the function 
    } 
} 

// execute getData if no event is fired in a 1000ms interval (the user stopped typing) 
// getData is the same that you have 
var fn = handler(1000, getData); 

$("#filter").change(fn);