2010-01-05 3 views
7

J'ai une zone de texte qui chaque fois qu'un utilisateur saisit une lettre, je fais une recherche avec une requête ajax et montre le résultat "live" pour l'utilisateur. Souvent, lorsqu'un utilisateur tape les lettres, il faut plus de temps pour que la demande soit faite que pour l'utilisateur d'entrer une nouvelle lettre, donc une nouvelle demande est faite avant que la première ne soit terminée. Ce serait beaucoup mieux si le premier pouvait se terminer avant de faire la prochaine demande. Existe-t-il un bon moyen de ne faire une nouvelle demande que si la dernière requête est terminée?Jquery demande ajax, attendez la dernière requête pour terminer

Ceci est mon code jquery:

$("#MyTextBox").change(function() { 
    if (this.value.length > 2) { 
     $.ajax({ 
      type: "GET", 
      url: "http://www.domain.com/Service.svc/Search?keyword=" + this.value, 
      dataType: "json", 
      success: function(data) { 
       //here I have some code that shows the result for the user 
      } 
     }); 
    } 
}); 

Répondre

9

Vous pouvez créer un booléen qui restera vrai ou faux selon qu'il y a déjà une demande. Définissez-le sur true lorsque vous lancez une requête et redéfinissez-la sur false dans votre fonction de rappel.

var request_in_process = false; 
$("#MyTextBox").change(function() { 
    if (this.value.length > 2 && !request_in_process) { 
     request_in_process = true; 
     $.ajax({ 
      type: "GET", 
      url: "http://www.domain.com/Service.svc/Search?keyword=" + this.value, 
      dataType: "json", 
      success: function(data) { 
       request_in_process = false; 
       //here I have some code that shows the result for the user 
      } 
     }); 
    } 
}); 
+0

Merci! C'était exactement ce que je cherchais. Mais pour une raison quelconque, lorsque je tape dans mon texte, il semble que chaque fois que j'entre une lettre, c'est un peu buggé et chaque lettre apparaît avec une sorte de retard. La requête ajax doit être envoyée async, cela ne devrait donc pas affecter la zone de texte. – Martin

+1

Il vaudrait mieux assigner une fonction avec un code de nettoyage comme 'request_in_progress' dans le paramètre' complete' plutôt que 'success' si la requête échoue. –

0

Vous pouvez utiliser ajaxComplete afin que vous sachiez quand une demande est terminée avant de faire une nouvelle demande.

Vous pouvez combiner ceci avec bind/unbind de sorte que l'événement change soit ajouté une fois manuellement, puis non lié lorsqu'une requête ajax démarre, et rebondit lorsque la requête ajax se termine.

8

Vous pouvez interrompre une requête AJAX. Gardez une trace de la requête en tant que variable et annulez-la avant de ré-initier la requête.

var request = $.ajax({ ... }); 
request.abort(); 

Ceci a l'avantage d'être plus réactif à l'entrée de l'utilisateur. Si l'utilisateur a tapé quelque chose de plus depuis que la première requête a été lancée, il ne se soucie probablement plus du premier ensemble de résultats. Abandonner et recréer la requête AJAX signifie que l'utilisateur obtient un meilleur ensemble de résultats.

0

Comme ceejayoz déjà mentionné, vous devez annuler la demande précédente. (En attente de la demande fera les utilisateurs fou s'ils ne peuvent pas taper comme ils veulent et préférant les demandes plus anciennes sur les nouvelles rend les résultats incohérents.). Alors qu'en est:

var request = null; 
//...  
$("#MyTextBox").change(function() { 
    if (this.value.length > 2) { 
     if (request && request.abort) 
      request.abort(); 
     request = $.ajax({ 
      type: "GET", 
      url: "http://www.domain.com/Service.svc/Search?keyword=" + this.value, 
      dataType: "json", 
      success: function(data) { 
      //here I have some code that shows the result for the user 
      request = null;     
     }); 
    }    
}); 
0

ici est un peu plus robuste la mise en oeuvre. Fondamentalement, nous sauvegardons l'objet ajax (c'est-à-dire l'objet de promesse) dans la fermeture afin que les appels ultérieurs puissent le regarder. Si les appels suivants trouvent que l'état de la demande est en attente, il ajoutera des rappels à cette demande en attente au lieu de générer une nouvelle demande. jQuery lancera tous les rappels dans la même séquence qu'ils ont été ajoutés. Cependant, il est possible que le même appelant tente de créer une demande encore et encore. Pour protéger contre cela, j'ai ajouté le paramètre callerId. Si le même appelant a fait une nouvelle demande alors que la demande précédente était encore en attente, nous ignorons simplement cette requête. Par souci d'exhaustivité, j'ai également ajouté cachedValues. Donc, si une requête ajax a déjà été faite, nous ne le faisons pas à nouveau.

var ajaxRequestor = function ($) { 
    "use strict"; 

    //privates 
    var cahedValues = {}; 
    var currentAjaxRequest, callers; 

    //public interface 
    return { 
     getData: function (callerId, onGet, onFail, forceRefresh) { 
      if (forceRefresh || !cahedValues.myData) { 

       //If there is a pending request, don't start new one 
       if (!currentAjaxRequest || currentAjaxRequest.state() != "pending") { 
        currentAjaxRequest = $.getJSON("data/MyData.json"); 
        callers = {}; //list of callers waiting for request 
       } 

       //if this caller is not in the list, add it and queue up its callbacks to existing request 
       if (!callers[callerId]) { 
        callers.callerId = callerId; 

        currentAjaxRequest.done(function (data, textStatus) { 
         cahedValues.myData = data; 
         onGet(data); 
        }); 

        currentAjaxRequest.fail(function (jqxhr, textStatus, error) { 
         if (!!onFail) { 
          onFail(error); 
         } 
         else throw error; 
        }); 
       } 
      } 
      else { 
       onGet(cahedValues.myData); 
      } 
     }, 

     invalidateMyData: function() { 
      delete cahedValues.myData; 
     } 
    }; 
})($); 
Questions connexes