55 votes

En attente de plusieurs appels asynchrones avant de continuer

Donc, j'ai une page qui charge et grâce à jquery.obtenir fait plusieurs demandes pour remplir des listes déroulantes avec leurs valeurs.

$(function() {
    LoadCategories($('#Category'));
    LoadPositions($('#Position'));
    LoadDepartments($('#Department'));

    LoadContact();
};

Il appelle ensuite LoadContact(); Qui ne un autre appel, et quand il revient il remplit tous les champs du formulaire. Le problème est que, souvent, les listes déroulantes ne sont pas tous remplis, et donc, il ne peut pas les mettre à la bonne valeur.

Ce dont j'ai besoin pour être en mesure de le faire, est en quelque sorte LoadContact exécuter uniquement une fois que les autres méthodes sont complètes et des rappels de service effectuée en cours d'exécution.

Mais, je ne veux pas avoir à mettre un tas de drapeaux à la fin de la liste déroulante de la population rappels, que je vérifie, et avoir un récursif appel de setTimeout vérifier, avant de faire appel à LoadContact();

Est-il quelque chose en jQuery qui me permet de dire, "Exécuter ce, lors de toutes ces sont faites."?

Plus D'Infos Je pense à quelque chose le long de ces lignes

$().executeAfter(
    function () {   // When these are done
        LoadCategories($('#Category'));
        LoadPositions($('#Position'));
        LoadDepartments($('#Department'));
    },
    LoadContact // Do this
);

...il aurait besoin de garder une trace des appels ajax qui se produisent lors de l'exécution des méthodes, et quand ils sont tous complets, appel LoadContact;

Si je savais comment intercepter ajax qui sont faits dans cette fonction, je pourrais probablement écrire une extension jQuery pour ce faire.

Ma Solution

;(function($) {
    $.fn.executeAfter = function(methods, callback) {

        var stack = [];

        var trackAjaxSend = function(event, XMLHttpRequest, ajaxOptions) {
            var url = ajaxOptions.url;

            stack.push(url);
        }

        var trackAjaxComplete = function(event, XMLHttpRequest, ajaxOptions) {
            var url = ajaxOptions.url;

            var index = jQuery.inArray(url, stack);

            if (index >= 0) {
                stack.splice(index, 1);
            }

            if (stack.length == 0) {
                callback();
                $this.unbind("ajaxComplete");
            }
        }

        var $this = $(this);

        $this.ajaxSend(trackAjaxSend)
        $this.ajaxComplete(trackAjaxComplete)

        methods();
        $this.unbind("ajaxSend");
    };
})(jQuery);

Cela se lie à la ajaxSend événement alors que les méthodes sont appelés et maintient une liste d'url (besoin d'une meilleure id unique si) qui sont appelés. Puis, il se délie de ajaxSend de sorte que seules les demandes qui nous intéresse ce sont suivies. Il se lie également à ajaxComplete et supprime les éléments de la pile de retour. Lorsque la pile atteint zéro, il exécute notre rappel, et délie les ajaxComplete événement.

43voto

Nick Craver Points 313913

Y .ajaxStop() así:

$(function() {
  $(document).ajaxStop(function() {
    $(this).unbind("ajaxStop"); //prevent running again when other calls finish
    LoadContact();
  });
  LoadCategories($('#Category'));
  LoadPositions($('#Position'));
  LoadDepartments($('#Department'));
});

T .ajaxStart() ,

17voto

KPD Points 23

L'expansion sur Tom Lianza réponse, $.when() est maintenant une bien meilleure façon d'accomplir ce que l'utilisation d' .ajaxStop().

Le seul inconvénient est que vous devez être sûr que les méthodes asynchrones, vous devez attendre au retour d'un Deferred object. Heureusement, ajax jQuery appelle déjà le faire par défaut. Afin de mettre en œuvre le scénario de la question, les méthodes qui doivent être attendu sur ressemblerait à quelque chose comme ceci:

function LoadCategories(argument){
    var deferred = $.ajax({
       // ajax setup
    }).then(function(response){ 
       // optional callback to handle this response 
    });
    return deferred;
}

Alors à appeler LoadContact() après trois appels ajax sont de retour et éventuellement exécuté leur propre rappels:

// setting variables to emphasize that the functions must return deferred objects
var deferred1 = LoadCategories($('#Category'));
var deferred2 = LoadPositions($('#Position'));
var deferred3 = LoadDepartments($('#Department'));

$.when(deferred1, deferred2, deferred3).then(LoadContact);

7voto

Tom Lianza Points 1802

Si vous utilisez Jquery 1.5 ou une version ultérieure, je pense que l'objet Deferred est la meilleure solution : http://api.jquery.com/category/deferred-object/

La méthode d'aide, when, est également très intéressante : http://api.jquery.com/jQuery.when/

0voto

Nikita Rybak Points 36641

Mais je ne veux pas avoir à mettre un tas de drapeaux à la fin des callbacks de la population déroulante, que je vérifie ensuite, et avoir un appel récursif setTimeout qui vérifie, avant d'appeler LoadContact() ;
Pas besoin de setTimeout. Il suffit de vérifier dans chaque callback que les trois listes sont remplies (ou mieux, de créer un compteur, de l'augmenter dans chaque callback et d'attendre qu'il soit égal à 3), puis d'appeler LoadContact à partir du callback. Cela me semble assez simple.

L'approche ajaxStop pourrait fonctionner également, mais je ne la connais pas très bien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X