7
votes

En attendant que l'événement soit traité pour continuer à exécuter la fonction qui a déclenché l'événement.

Je recherche une solution élégante et efficace à mon problème:

J'ai cette webapp avec de nombreux composants; p>

Un composant principal comprend de nombreux ajouts qui vont se développer / évoluer avec le temps.

Ce composant principal a une fonction dans laquelle avant de faire ce qu'il est censé faire, il déclenche un événement Beforedo afin que les addons puissent écouter. P>

//app
var $doc = $(document.body); 


//component    
$doc.on({
    wait: function (e) { ++$doc.component.handleinprogress; },

    addonready: function () {
        --$doc.component.handleinprogress;
        if ($doc.component.handleinprogress==0) $doc.trigger('readyfordo');
    },

    readyfordo: function () {
        //do stuff after event has been handled by the addons 
    }        
});

$doc.component = {
    handleinprogress: 0,
    dostg: function () {

        $doc.component.handleinprogress = 0;
        $doc.trigger('beforedo');
    }
};

//in component addon files

$doc.on('beforedo', function (e) {

    $doc.trigger('wait');
    //do addon stuff
    $doc.trigger("addonready");
}


0 commentaires

4 Réponses :


8
votes

Pour attendre que tous les gestionnaires finissent avant d'exécuter du code, vous devez utiliser l'API REFERRED DE JQRERY. Vous pouvez faire quelque chose comme ceci: XXX

En outre, JQuery's déclencheur < / code> vous permet de passer des paramètres supplémentaires. Passez une fonction qui sera la fonction de rappel.

Votre code final devrait ressembler à quelque chose comme ceci: xxx

Si besoin est, quand vous appelez < Code> Callback () Vous pouvez même passer à tout résultat que vous devrez peut-être passer comme un argument. En conséquence, modifiez la signature de fonction dans votre .Trigger () appelez aussi.

Développer sur le commentaire Si vous avez laissé ci-dessous, vous pouvez avoir une fonction de chargeur courant si vous aimez: xxx

voir:

jquery différé
jquery.Lorsque ()
jquery.trigger


6 commentaires

Ouais mais alors où est la modularité? Je pense que c'est son problème, il a plusieurs addons avec des fermetures / contextes séparés et ne veut pas que le module principal dépend de les addons, mais de l'inverse.


Dans mon exemple ci-dessus, le $. Quand () n'a pas besoin d'avoir les appels Ajax. Il peut plutôt être à une fonction de chargeuse commune qui renvoie le $. Ajax Promise en faisant la fabrication $. Quand (chargez ("Fichier1"), chargez ("Fichier2"))


Yup, c'est bien. De cette façon, il peut retourner une promesse, non seulement $. Ajax . Je déteste toujours en utilisant une promesse où il n'y a pas d'appels asynchrones à partir de ...


va tester $ doc.trigger ('beforedo', fonction () {... pour comprendre comment cela fonctionne; NB: effectivement les addons n'impliquent pas nécessairement de chargement de données externes, pourraient être n'importe quoi (calculs, Regex Remplacer, DOM Access et Modifier) ​​qui doivent être complètes avant que le maintien ne se poursuive avec son travail


S'il vous plaît voir mon édition & Apo à nouveau pour faire les choses l'autre sens


J'ai compris le rappel de la gâchette grâce à cela, je ne savais pas, mais cela ne correspond pas totalement à mon objectif; Je pense que je vais aller pour un mélange de votre solution de solution et @legec afin de donner à la prime? bien (pensant que je tape) depuis que Legec a moins de points et a fait une réponse plus longue et plus détaillée, désolé devait choisir



3
votes

Consultez mon fidou ici . Votre idée de compter les demandes finies est bonne, c'est juste une question de code structurant. Sachant que vous avez besoin de "modules / addons" découplés, c'est la façon dont j'irais: xxx

Utilisation de cette méthode, les addons peuvent avoir quelque chose en eux, il suffit de notifier "Main" quand Ils finissent ce qu'ils ont besoin de faire.

Si j'étais vous, j'irais encore plus loin et que j'extraîtrais tout le code "gestionnaires" dans "Main" dans une classe distincte instanciée en tant que propriété publique dans "Main" avec AfterDoSTG en tant que paramètre. De cette façon, vous ne polut pas de code d'application avec méta truc comme celui-ci.


4 commentaires

Ce n'est pas à moitié mauvais, je suggérerais un léger changement cependant: dans ce cas, les add-ons doivent savoir sur le principal . Pour supprimer cette limitation, vous pouvez utiliser un événement Beforedodone . Vous déclenchez ceci dans les add-ons, quand ils sont terminés. Vous ajoutez un auditeur à cet événement dans le principal et vous décrémentez le compteur dans cet écouteur (et vous appelez le rappel de cet auditeur bien sûr). Qu'en penses-tu?


Mon code initial a utilisé cela, mais alors j'ai décidé que c'est un peu trop pour un POC. Mais oui, si vous avez besoin de plus de découplage, c'est la voie à suivre: jsfiddle.net/cvqdx/4


En réalité et je m'excuse de ne pas mettre à jour la question avant de mettre la prime, mais j'ai choisi d'aller pas longtemps après la question (et n'abandonnez pas de réponse à cette époque) avec quelque chose de très similaire @balintbako Solution; testera toutes les réponses données et voir laquelle que je préfère (en termes de performance - pour l'utilisateur et le codeur -> c.-à-d. Élégance "directe" et code)


S'il vous plaît voir mon édition & Apo à nouveau pour faire les choses l'autre sens



1
votes

La solution que vous utilisez ne fonctionne pas correctement. Si vous avez 2 addons, le 1er reçoit l'événement et registre 'Wait', puis le même appelle Readyfordo. Que se passe-t-il avec le 2e? Il n'aura pas la chance d'intro.

Chacun de vos addons doit s'ajouter à une matrice globale et lorsque vous jetez votre événement, vous devez gérer le cas lorsqu'il n'y a rien dans le tableau, sinon vous utilisez le même code. Dans votre solution sans utiliser le guichet de la poignéeProgresse, utilisez plutôt la longueur de la matrice.

Vous pouvez également être intéressé par le modèle de promesse (voir objet différé dans JQuery Doc) qui rendent l'attente de manière asynchrone à un "événement "Une brise.

http://api.jquerery.com/category / objet différé /

http: //api.jQuery. com / repored.Promise / xxx

appeler: xxx

aussi simple que cela.


4 commentaires

non, il fonctionne, tous les addons gèrent l'événement non seulement le premier ou le dernier (lorsqu'ils sont inscrits de toute évidence) et que chacun déclenche une attente manipulée par le composant Père incrémentant le compteur et car il y a toujours au moins un addon qui est faire quelque chose (ce qui me permet de ne pas ajouter de gestionnaire aux addons qui n'en ont pas besoin d'un - si je ajoute une manutention inutile, assurez-vous que AddonReady est déclenché au moins une fois, j'ai besoin d'un ensemble (1) avant de déclencher l'ajout Pour vous assurer que toute attente est déclenchée avant qu'un addonready est déclenché.


Pouvez-vous développer à l'aide d'un tableau (efficacement et asynchrone)?


Le tableau fait simplement référence à tous les objets des plugins (ils doivent être des objets). Chaque objet a des méthodes de plugin communes que votre «événement» peut appeler au lieu d'utiliser des événements DOM. La méthode init renvoie une promesse et dans la méthode "événement" que vous attendez de manière asynchrone pour que toutes les promesses soient "faites". Aussi simple que cela. Voir mon lien vers différé / promesses.


ok cela pourrait ressembler au début d'une amélioration de mon code et franchement suffisamment pour accepter la réponse, mais franchement pas assez pour la Bounty et mes points gagnés (désolé) car il ne correspond pas aux spécifications qui ne correspondent pas aux spécifications: ce n'est pas un Événement instantané -> La plupart addon n'ont pas de travail à faire sur cet événement composant (seulement certains ont, et parfois non) - s'il vous plaît pour la prime adapter cette idée à ma structure et spécifications de code



3
votes

Softlion a souligné plusieurs points, avec lesquels je suis d'accord.

Problèmes potentiels:

Un problème peut survenir avec votre implémentation actuelle, si l'un de vos addons appelle $ doc.trigger ("addonready"); synchrone : < / p> xxx

Dans ce cas, en fonction de l'ordre de résolution de vos rappels, vous pouvez déclencher accidentellement votre événement ReadyFordo après que le premier addon ait déclenché son AddonReady fonction, et avant que la seconde ait eu une modification de la gâchette attendre .

Votre code s'appuie également sur l'hypothèse que tous vos addons seront toujours exécutés Exactement un .trigger ('Addonready') pour chaque .trigger ('wait') . Je ne sais pas comment votre code ressemble, ni combien d'addons que vous avez, mais en vous assurant que c'est le cas pour chaque chemin d'exécution possible est un obstacle à un obstacle (par exemple: avez-vous testé le 2 ^ n cas de défaillance si vous avez n ajax appels?)

Tant que tout votre code est en interne, vous pouvez en avoir le contrôle, mais cela semble-t-il cassant .

Les différés / promesses de JQuery:

Un modèle générique consiste à utiliser les promesses de JQuery. Tous les appels asynchrones de JQuery's sont maintenant enveloppés dans des promesses et la bibliothèque propose une API qui permettra de manipuler les personnes de manière assez élégante - et il a probablement été testé dans plus de cas de coin que votre propre code.

Voici mes 2 cents: xxx

au lieu d'utiliser votre Beforedo , attendre , addonready Événements, vous avez vos plugins enregistrez une fonction dans un inadqueue connu par votre composant - Notez que vous pouvez choisir pas pour enregistrer le rappel si votre addon n'a pas besoin un.

à peu près parlant: Dans vos addons, vous remplacez $ doc.on ('Beforedo', fonction () {...}) avec $ doc. composant.initqueue.push (fonction () {...}) , et si vous avez besoin d'attendre quelque chose, vous retournez une promesse autour de ce quelque chose.

Vous pouvez ensuite laisser le < CODE> $. Quand () La fonction prenne soin de tout ensemble et attendez ce qui devrait être attendu.

mise à jour : effectivement, $. à poule attend les promesses comme des arguments distincts

si stockés dans un tableau, vous devez appeler $. Quand.Appliquez ($, tableau) pour adapter la signature de la fonction .

$. Quand (tableau) considérera que son argument (le tableau) n'est pas une promesse, et résolve immédiatement.

violon


3 commentaires

J'utilise un Settimeout pour déclencher AddonReady si STG mais pas Ajax, pas vraiment un problème, pas si élégant, je suis d'accord pourquoi je cherche une autre façon. Il manque quelque chose dans votre code, c'est le cas où le tableau de la fonction est vide (à moins qu'un tableau vide n'est considéré comme résolu par quand () ??)


@mikakun: oui, quand () traitera des non-promesses comme "résolues" et déclenchera également .commlete si vous donnez une liste de paramètres vide. Je n'avais pas testé mon code, $. Quand attend effectivement des arguments distincts (pas un tableau). Vous devrez utiliser $. Quand.Appliquez ($, tableau) pour alimenter un tableau (moins élégant).


Bounty à vous pour une belle explication sur l'utilisation de la promesse et accepter à Xbonez pour m'apprendre le rappel de la gâchette qui sera utile aussi, je pense