Je passe des rappels ou je déclenche simplement les fonctions d'autres fonctions de mes programmes pour que les choses se passent une fois les tâches terminées. Quand quelque chose finit, je déclenche la fonction directement:
var ground = 'clean';
function shovelSnow(){
console.log("Cleaning Snow");
ground = 'clean';
}
function makeItSnow(){
console.log("It's snowing");
ground = 'snowy';
shovelSnow();
}
Mais j'ai lu beaucoup de stratégies de programmation différentes, et celle que je comprends puissante, mais que je n'ai pas encore pratiquée, est basée sur des événements (je pense qu'une méthode que j'ai lue s'appelait "pub-sub" ):
var ground = 'clean';
function shovelSnow(){
console.log("Cleaning Snow");
ground = 'clean';
}
function makeItSnow(){
console.log("It's snowing");
ground = 'snowy';
$(document).trigger('snow');
}
$(document).bind('snow', shovelSnow);
J'aimerais comprendre les forces et les faiblesses objectives de la programmation événementielle, par opposition à simplement appeler toutes vos fonctions à partir d'autres fonctions. Dans quelles situations de programmation la programmation événementielle a-t-elle un sens?
event-programming
Viziionary
la source
la source
$(document).bind('snow', shovelShow)
. Pas besoin de l'envelopper dans une fonction anonyme.Réponses:
Un événement est une notification décrivant une occurrence du passé récent.
Une implémentation typique d'un système piloté par événement utilise un répartiteur d'événement et des fonctions de gestionnaire (ou abonnés ). Le répartiteur fournit une API pour relier les gestionnaires aux événements (jQuery
bind
) et une méthode pour publier un événement à ses abonnés (trigger
dans jQuery). Lorsque vous parlez d'événements IO ou UI, il existe généralement une boucle d'événements , qui détecte les nouveaux événements tels que les clics de souris et les transmet au répartiteur. Dans JS-land, le répartiteur et la boucle d'événement sont fournis par le navigateur.Pour le code qui interagit directement avec l'utilisateur - répondre aux pressions sur les touches et aux clics - la programmation événementielle (ou une variante de celle-ci, telle que la programmation réactive fonctionnelle ) est presque inévitable. En tant que programmeur, vous ne savez pas quand et où l'utilisateur va cliquer. Vous devez donc utiliser le framework d'interface graphique ou le navigateur pour détecter l'action de l'utilisateur dans sa boucle d'événements et notifier votre code. Ce type d'infrastructure est également utilisé dans les applications réseau (cf. NodeJS).
Votre exemple, dans lequel vous soulevez un événement dans votre code plutôt que d'appeler directement une fonction, présente des compromis plus intéressants, dont je parlerai plus loin. La principale différence est que l'éditeur d'un événement (
makeItSnow
) ne spécifie pas le destinataire de l'appel. c'est câblé ailleurs (dans l'appel àbind
votre exemple). C'est ce qu'on appelle feu et oublie :makeItSnow
annonce au monde qu'il neige, mais peu importe qui écoute, ce qui se passe ensuite ou quand cela se produit, il diffuse simplement le message et se dépoussière.Ainsi, l'approche événementielle dissocie l'expéditeur du message du destinataire. Un avantage que cela vous offre est qu'un événement donné peut avoir plusieurs gestionnaires. Vous pouvez lier une
gritRoads
fonction à votre événement neige sans affecter leshovelSnow
gestionnaire existant . Vous avez la flexibilité dans la manière dont votre application est câblée; pour désactiver un comportement, il vous suffit de supprimer l'bind
appel plutôt que de parcourir le code pour en trouver toutes les instances.Un autre avantage de la programmation événementielle réside dans le fait qu’elle vous donne un endroit où placer vos préoccupations transversales. Le répartiteur d'événements joue le rôle de médiateur et certaines bibliothèques (telles que Brighter ) utilisent un pipeline afin que vous puissiez facilement brancher des exigences génériques telles que la journalisation ou la qualité de service.
Divulgation complète: Brighter est développé à Huddle, où je travaille.
Un troisième avantage de découplage de l'expéditeur d'un événement du récepteur est qu'il vous donne la flexibilité lorsque vous gérez l'événement. Vous pouvez traiter chaque type d'événement sur son propre thread (si votre répartiteur d'événements le prend en charge) ou vous pouvez placer les événements déclenchés sur un courtier de messages tel que RabbitMQ et les gérer avec un processus asynchrone, voire les traiter en bloc du jour au lendemain. Le destinataire de l'événement peut se trouver dans un processus séparé ou sur une machine séparée. Vous n'avez pas à changer le code qui déclenche l'événement pour le faire! C'est la grande idée derrière les architectures de "microservices": des services autonomes communiquent à l'aide d'événements, avec un middleware de messagerie comme épine dorsale de l'application.
Pour un exemple assez différent de style piloté par les événements, reportez-vous à la conception pilotée par domaine , où les événements de domaine sont utilisés pour aider à garder les agrégats séparés. Par exemple, considérons un magasin en ligne qui recommande des produits en fonction de votre historique d’achat. A
Customer
doit avoir son historique d’achats mis à jour lorsqu’unShoppingCart
paiement est effectué. L'ShoppingCart
agrégat peut notifier leCustomer
en soulevant unCheckoutCompleted
événement; leCustomer
serait mis à jour dans une transaction séparée en réponse à l'événement.Le principal inconvénient de ce modèle événementiel est l’indirection. Il est maintenant plus difficile de trouver le code qui gère l'événement car vous ne pouvez pas y accéder simplement à l'aide de votre IDE; vous devez déterminer où l'événement est lié dans la configuration et espérer que vous avez trouvé tous les gestionnaires. Il y a plus de choses à garder dans la tête à tout moment. Les conventions de style de code peuvent être utiles ici (par exemple, placer tous les appels
bind
dans un fichier). Pour des raisons de santé mentale, il est important de n'utiliser qu'un seul répartiteur d'événements et de l'utiliser de manière cohérente.Un autre inconvénient est qu’il est difficile de modifier les événements. Si vous devez modifier le format d'un événement, vous devez également modifier tous les destinataires. Cela est exacerbé lorsque les abonnés d'un événement se trouvent sur différentes machines, car vous devez maintenant synchroniser les versions de logiciels!
Dans certaines circonstances, la performance peut être une préoccupation. Lors du traitement d'un message, le répartiteur doit:
Ceci est certainement plus lent qu'un appel de fonction normal, qui consiste uniquement à pousser un nouveau cadre sur la pile. Cependant, la flexibilité offerte par une architecture pilotée par les événements facilite beaucoup l'isolement et l'optimisation du code lent. Avoir la possibilité de soumettre du travail à un processeur asynchrone est une grande victoire ici, car cela vous permet de servir une demande immédiatement alors que le travail acharné est traité en arrière-plan. Quoi qu’il en soit, si vous interagissez avec la base de données ou si vous dessinez à l’écran, les coûts liés aux E / S vont totalement couvrir les coûts de traitement d’un message. Il s'agit d'éviter une optimisation prématurée.
En résumé, les événements sont un excellent moyen de créer des logiciels à couplage lâche, mais ils ne sont pas sans coût. Ce serait une erreur, par exemple, de remplacer chaque appel de fonction dans votre application par un événement. Utilisez les événements pour créer des divisions architecturales significatives.
la source
La programmation basée sur les événements est utilisée lorsque le programme ne contrôle pas la séquence d'événements qu'il exécute. Au lieu de cela, le flux de programme est dirigé par un processus externe tel qu'un utilisateur (par exemple une interface graphique), un autre système (par exemple un client / serveur) ou un autre processus (par exemple un RPC).
Par exemple, un script de traitement par lots sait ce qu'il doit faire, il le fait simplement. Ce n'est pas événementiel.
Un traitement de texte est assis à cet endroit et attend que l'utilisateur commence à taper. Les touches sont des événements qui déclenchent une fonctionnalité permettant de mettre à jour le tampon de document interne. Le programme ne peut pas savoir ce que vous voulez taper, il doit donc être événementiel.
La plupart des programmes d'interface graphique sont pilotés par les événements car ils sont construits autour de l'interaction utilisateur. Cependant, les programmes événementiels ne se limitent pas aux interfaces graphiques, c'est simplement l'exemple le plus familier pour la plupart des gens. Les serveurs Web attendent que les clients se connectent et suivent un idiome similaire. Les processus en arrière-plan sur votre ordinateur peuvent également réagir à des événements. Par exemple, un analyseur de virus à la demande peut recevoir un événement du système d'exploitation concernant un fichier nouvellement créé ou mis à jour, puis analyser ce fichier à la recherche de virus.
la source
Dans une application basée sur les événements, le concept d’ écouteurs d’événements vous donnera la possibilité d’écrire encore plus d’ applications lâchement couplées .
Par exemple, un module ou un plug-in tiers peut supprimer un enregistrement de la base de données, puis déclencher l'
receordDeleted
événement et laisser le reste aux écouteurs d'événement faire leur travail. Tout fonctionnera bien, même si le module déclencheur ne sait même pas qui est à l'écoute de cet événement en particulier ni de ce qui devrait se passer par la suite.la source
Une simple analogie que je voulais ajouter qui m'a aidé:
Pensez aux composants (ou objets) de votre application comme à un grand groupe d'amis Facebook.
Lorsqu'un de vos amis veut vous dire quelque chose, il peut vous appeler directement ou le poster sur son mur Facebook. Quand ils le publient sur leur Facebook, tout le monde peut le voir et y réagir, mais beaucoup ne le font pas. Parfois, il est important que les gens réagissent, comme "Nous allons avoir un bébé!" ou "Un tel groupe fait un concert surprise au bar Drunkin 'Clam!". Dans ce dernier cas, le reste des amis devront probablement réagir, en particulier s’ils sont intéressés par ce groupe.
Si votre ami veut garder un secret entre vous et eux, ils ne le publieraient probablement pas sur leur mur Facebook, ils vous contacteraient directement pour vous le dire. Imaginez un scénario dans lequel vous dites à une fille que vous aimez que vous souhaitez la rencontrer dans un restaurant pour un rendez-vous. Au lieu de l'appeler directement et de lui demander, affichez-la sur votre mur Facebook pour que tous vos amis puissent la voir. Cela fonctionne, mais si vous avez un ex jaloux, alors elle pourrait le voir et apparaître au restaurant pour gâcher votre journée.
Lorsque vous décidez d'intégrer ou non des écouteurs d'événements pour implémenter quelque chose, pensez à cette analogie. Ce composant doit-il mettre son activité à la portée de tous? Ou ont-ils besoin d'appeler quelqu'un directement? Les choses peuvent se gâter assez facilement, alors faites attention.
la source
Cette analogie suivante pourrait vous aider à comprendre la programmation d'E / S pilotée par les événements en traçant un parallèle avec la file d'attente à la réception du médecin.
Le blocage des E / S revient à dire que si vous êtes dans la file d'attente, la réceptionniste demande à un gars en face de vous de remplir le formulaire et elle attend jusqu'à ce qu'il ait terminé. Vous devez attendre votre tour jusqu'à ce que le gars termine sa forme, cela bloque.
Si un célibataire met trois minutes à remplir, le dixième doit attendre 30 minutes. Maintenant, pour réduire ce temps d’attente du 10ème gars, la solution serait d’augmenter le nombre de réceptionnistes, ce qui est coûteux. C'est ce qui se passe dans les serveurs Web traditionnels. Si vous demandez des informations sur l'utilisateur, les autres utilisateurs devront attendre que l'opération en cours, à partir de la base de données, soit terminée. Cela augmente le "délai de réponse" de la dixième demande et augmente exponentiellement pour le nième utilisateur. Pour éviter cela, les serveurs Web traditionnels créent un thread (équivalent à un nombre croissant de réceptionnistes) pour chaque requête, c’est-à-dire qu’il crée fondamentalement une copie du serveur pour chaque requête, ce qui représente un coût élevé en consommation de processeur, car chaque requête nécessite un système d’exploitation. fil. Pour mettre à l'échelle l'application,
Event Driven : L'autre approche pour augmenter le "temps de réponse" de la file d'attente consiste à opter pour une approche événementielle, où le gars dans la file d'attente sera remis au formulaire, il lui sera demandé de remplir et de revenir à la fin. Par conséquent, la réceptionniste peut toujours prendre une demande. C’est exactement ce que fait javascript depuis sa création. Dans le navigateur, javascript répond aux événements de clic, défilement, balayage ou extraction de la base de données, etc. Cela est possible en javascript de manière inhérente, car javascript traite les fonctions en tant qu'objets de première classe et peut être transmis en tant que paramètre à d'autres fonctions (appelées rappels) et peut être appelé à la fin d'une tâche particulière. C'est exactement ce que fait node.js sur le serveur. Vous trouverez plus d'informations sur la programmation par événement et le blocage d'E / S dans le contexte du nœud ici
la source