Tenho passado callbacks ou apenas acionado as funções de outra função em meus programas para fazer as coisas acontecerem após a conclusão das tarefas. Quando algo termina, eu aciono a função diretamente:

 var ground = "clean"; function shovelSnow(){ console.log("Cleaning Snow"); ground = "clean"; } function makeItSnow(){ console.log("It"s snowing"); ground = "snowy"; shovelSnow(); }  

Mas eu tenho li sobre muitas estratégias diferentes em programação, e uma que entendo ser poderosa, mas ainda não pratiquei, é baseada em eventos (acho que um método sobre o qual li foi chamado de “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);  

Eu gostaria de entender os pontos fortes e fracos do evento programação baseada em, em vez de apenas chamar todas as suas funções de dentro de outras funções. Em quais situações de programação a programação baseada em eventos faz sentido usar?

Comentários

  • Como um aparte, você pode apenas usar $(document).bind('snow', shovelShow). Não há necessidade de envolvê-lo em uma função anônima.
  • Você também pode estar interessado em aprender sobre a ” programação reativa “, que tem muito em comum com a programação baseada em eventos.

Resposta

Um evento é uma notificação que descreve uma ocorrência do passado recente.

Uma implementação típica de um sistema orientado a eventos utiliza um dispatcher de evento e funções de manipulador (ou assinantes ). O dispatcher fornece uma API para conectar manipuladores a eventos (jQuery “s bind) e um método para publicar um evento para seus assinantes (trigger em jQuery). Quando você está falando sobre eventos de IO ou IU, normalmente há também um loop de eventos , que detecta novos eventos, como cliques do mouse e os passa para o despachante. JS-land, o despachante e o loop de evento são fornecidos pelo navegador.

Para código que interage diretamente com o usuário – respondendo a pressionamentos de tecla e cliques – programação orientada a eventos (ou uma variação disso, como programação funcional reativa ) é quase inevitável. Você, o programador, não tem ideia de quando ou onde o usuário irá clicar, então é tudo para a estrutura da GUI ou navegador para detectar a ação do usuário em seu loop de evento e notificar seu código. Este tipo de infraestrutura também é usado em aplicativos de rede (cf NodeJS).

Seu exemplo, em que você levanta um evento em você nosso código , em vez de chamar uma função diretamente, tem algumas compensações mais interessantes, que discutirei a seguir. A principal diferença é que o editor de um evento (makeItSnow) não especifica o destinatário da chamada; isso está conectado em outro lugar (na chamada para bind em seu exemplo). Isso é chamado de dispare e esqueça : makeItSnow anuncia ao mundo que está nevando, mas não se importa quem está ouvindo, o que acontece a seguir ou quando acontece – ele simplesmente transmite a mensagem e limpa o pó de suas mãos.


Portanto, a abordagem baseada em eventos separa o remetente da mensagem do destinatário. Uma vantagem que isso oferece é que um determinado evento pode ter vários manipuladores. Você poderia vincular uma função gritRoads ao seu evento de neve sem afetar o manipulador shovelSnow existente. Você tem flexibilidade na maneira como seu aplicativo é conectado; para desligar um comportamento, você só precisa remover a chamada bind em vez de procurar no código para encontrar todas as instâncias do comportamento.

Outra vantagem de a programação orientada a eventos é que ela fornece um lugar para colocar questões transversais. O despachante de eventos desempenha o papel de Mediador e algumas bibliotecas (como Brighter ) utilizam um pipeline para que você possa facilmente inserir requisitos genéricos, como registro ou qualidade de serviço.

Divulgação completa: Brighter é desenvolvido na Huddle, onde trabalho.

Uma terceira vantagem de separar o remetente de um evento do receptor é que isso lhe dá flexibilidade em quando você trata o evento. Você pode processar cada tipo de evento em seu próprio encadeamento (se o seu dispatcher de evento suportar) ou pode colocar eventos gerados em um agente de mensagens, como RabbitMQ e trate-os com um processo assíncrono ou mesmo processe-os em massa durante a noite. O receptor do evento pode estar em um processo separado ou em uma máquina separada. Você não precisa alterar o código que gera o evento para fazer isso! Esta é a grande ideia por trás das arquiteturas de “microsserviço”: serviços autônomos se comunicam usando eventos, com o middleware de mensagens como a espinha dorsal do aplicativo.

Para obter um exemplo bastante diferente de estilo orientado a eventos, observe o design orientado a domínio, onde eventos de domínio são usados para ajudar a manter os agregados separados. Por exemplo, considere uma loja online que recomenda produtos com base em seu histórico de compras. Um Customer precisa ter seu histórico de compras atualizado quando um ShoppingCart é pago. O ShoppingCart agregado pode notificar o Customer gerando um evento CheckoutCompleted; o Customer seria atualizado em uma transação separada em resposta ao evento.


A principal desvantagem deste modelo baseado em evento é a indireção. Agora é mais difícil encontrar o código que manipula o evento porque você não pode simplesmente navegar até ele usando seu IDE; você tem que descobrir onde o evento está vinculado na configuração e esperar ter encontrado todos os manipuladores. Há mais coisas para manter em sua cabeça a qualquer momento. As convenções de estilo de código podem ajudar aqui (por exemplo, colocar todas as chamadas para bind em um arquivo). Para o bem da sua sanidade, é importante usar apenas um dispatcher de eventos e de forma consistente.

Outra desvantagem é que é difícil refatorar eventos. Se você precisar alterar o formato de um evento, também precisará alterar todos os receptores. Isso é exacerbado quando os assinantes de um evento estão em máquinas diferentes, porque agora você precisa sincronizar os lançamentos de software!

Em certas circunstâncias, o desempenho pode ser uma preocupação. Ao processar uma mensagem, o despachante deve:

  1. Pesquisar os manipuladores corretos em alguma estrutura de dados.
  2. Construir um pipeline de processamento de mensagens para cada manipulador. Isso pode envolver várias alocações de memória.
  3. Chame dinamicamente os manipuladores (possivelmente usando reflexão se a linguagem exigir).

Certamente, é mais lento do que uma função regular chamada, que envolve apenas o envio de um novo quadro na pilha. No entanto, a flexibilidade que uma arquitetura orientada a eventos oferece torna muito mais fácil isolar e otimizar código lento. Ter a capacidade de enviar trabalho para um processador assíncrono é uma grande vitória aqui, pois permite atender a uma solicitação imediatamente enquanto o trabalho árduo é tratado em segundo plano. Em qualquer caso, se você “estiver interagindo com o banco de dados ou desenhando coisas na tela, os custos de IO irão inundar totalmente os custos de processamento de uma mensagem. É o caso de evitar uma otimização prematura.


Em resumo, os eventos são uma ótima maneira de construir softwares fracamente acoplados, mas eles têm um custo. Seria um erro, por exemplo, substituir cada chamada de função em seu aplicativo por um evento. Use eventos para criar divisões arquitetônicas significativas.

Comentários

  • Esta resposta diz o mesmo que 5377 ‘ s resposta que selecionei como correta; Eu ‘ estou mudando minha seleção para marcar esta porque ela é mais elaborada.
  • A velocidade é uma desvantagem significativa do código orientado a eventos? Parece que poderia ser, mas eu não ‘ não sei.
  • @ raptortech97 certamente pode ser. Para código que precisa ser particularmente rápido, você provavelmente deseja evitar o envio de eventos em um loop interno; felizmente, em tais situações é geralmente bem definido o que você precisa fazer, então você não ‘ não precisa da flexibilidade extra de eventos (ou publicar / assinar ou observadores, que são mecanismos equivalentes com terminologia diferente).
  • Observe também que existem algumas linguagens (por exemplo, Erlang) construídas em torno do modelo de ator onde tudo são mensagens (eventos). Nesse caso, o compilador pode decidir se deseja implementar as mensagens / eventos como chamadas de função diretas ou como comunicação.
  • Para ” desempenho ” Acho que precisamos distinguir entre desempenho de thread único e escalabilidade. Mensagens / eventos podem ser piores para desempenho de thread único (mas podem ser convertidos em chamadas de função para custo adicional zero e não ser piores), e para escalabilidade, ‘ é superior em praticamente todos forma (por exemplo, provavelmente resultará em melhorias massivas de desempenho em sistemas multi-CPU modernos e futuros ” many-CPU “).

Resposta

A programação baseada em eventos é usada quando o programa não controla a sequência de eventos que executa. Em vez disso, o fluxo do programa é direcionado por um processo externo, como um usuário (por exemplo, GUI), outro sistema (por exemplo, cliente / servidor) ou outro processo (por exemplo, RPC).

Por exemplo, um script de processamento em lote sabe o que precisa fazer, então simplesmente o faz. Ele não é baseado em eventos.

Um processador de texto fica lá e espera o usuário começar a digitar.Os pressionamentos de tecla são eventos que acionam a funcionalidade para atualizar o buffer interno do documento. O programa não pode saber o que você deseja digitar, portanto, deve ser orientado a eventos.

A maioria dos programas GUI são orientados a eventos porque são construídos em torno da interação do usuário. No entanto, os programas baseados em eventos não se limitam a GUIs, que são simplesmente o exemplo mais familiar para a maioria das pessoas. Os servidores da Web esperam que os clientes se conectem e seguem um idioma semelhante. Processos em segundo plano em seu computador também podem responder a eventos. Por exemplo, um verificador de vírus sob demanda pode receber um evento do sistema operacional relacionado a um arquivo recém-criado ou atualizado e, em seguida, verificar a existência de vírus nesse arquivo.

Resposta

Em um aplicativo baseado em evento, o conceito de Ouvintes de eventos permitirá que você escreva ainda mais Aplicativos Loosely Coupled .

Por exemplo, um módulo ou plug-in de terceiros pode excluir um registro do banco de dados e, em seguida, acionar o receordDeleted evento e deixar o resto para os ouvintes de evento fazerem seu trabalho. Tudo funcionará bem, mesmo que o módulo de acionamento nem saiba quem está ouvindo esse evento em particular ou o que deve acontecer a seguir.

Resposta

Uma analogia simples que eu queria adicionar que me ajudou:

Pense nos componentes (ou objetos) do seu aplicativo como um grande grupo de amigos do Facebook.

Quando um de seus amigos deseja lhe dizer algo, eles podem ligar diretamente para você ou postar em seu mural do Facebook. Quando eles postam no Facebook, qualquer pessoa pode ver e reagir a isso, mas muitas pessoas não. Às vezes é algo importante que as pessoas provavelmente precisem reagir a isso, como “Vamos ter um bebê!” ou “Fulano de tal banda está fazendo um show surpresa no Drunkin “Barra de mexilhões!”. No último caso, o resto dos amigos provavelmente precisará reagir a isso, especialmente se estiverem interessados na banda.

Se o seu amigo quiser manter um segredo entre você e eles, provavelmente não postariam no mural do Facebook, eles ligariam diretamente para você e avisariam. Imagine um cenário em que você diz a uma garota que gosta que gostaria de conhecê-la em um restaurante. Em vez de ligar diretamente para ela e perguntar ela, você publica no seu mural do Facebook para que todos os seus amigos vejam. Isso funciona, mas se você tiver um ex ciumento, ela poderá ver isso e aparecer no restaurante para estragar o seu dia.

Quando decidir se deve ou não incluir ouvintes de eventos para implementar algo, pense sobre esta analogia. Esse componente precisa divulgar seu negócio para qualquer pessoa ver? Ou eles precisam ligar diretamente para alguém? As coisas podem ficar complicadas facilmente, então seja cuidado.

Resposta

Esta analogia a seguir pode ajudá-lo u compreender a programação de E / S orientada por eventos, traçando um paralelo com a fila de espera na recepção do médico.

Bloquear I / O é como, se você está na fila, a recepcionista pede a um cara na sua frente para preencher o formulário e ela espera até ele terminar. Você tem que esperar pela sua vez até que o cara termine o formulário, isso está bloqueando.

Se o cara solteiro demorar 3 minutos para preencher, o décimo cara tem que esperar até 30 minutos. Agora, para reduzir esse décimo tempo de espera de caras, a solução seria aumentar o número de recepcionistas, o que é caro. É o que acontece nos servidores web tradicionais. Se você solicitar informações de um usuário, a solicitação subsequente de outros usuários deve esperar até o a operação atual, buscando no banco de dados, é concluída. Isso aumenta o “tempo de resposta” da 10ª solicitação e aumenta exponencialmente para o enésimo usuário. Para evitar isso, os servidores da web tradicionais criam thread (equivalente a aumentar o número de recepcionistas) para cada solicitação , ou seja, basicamente, ele cria uma cópia do servidor para cada solicitação, o que é caro em termos de consumo de CPU, já que cada solicitação precisará de um thread de sistema operacional. Para escalar o aplicativo, você teria que jogar muito poder de computação no aplicativo .

Orientado a eventos : a outra abordagem para aumentar o tempo de resposta “s” da fila é vá para uma abordagem orientada a eventos, onde os caras na fila serão entregues ao formulário, solicitado para preencher e voltar após o preenchimento. Portanto, a recepcionista pode sempre atender a solicitação. Isso é exatamente o que o javascript tem feito desde seu início. No navegador, o javascript responde ao evento de clique do usuário, rolar, deslizar ou buscar banco de dados e assim por diante. Isso é possível em javascript inerentemente, porque javascript trata as funções como primeira classe objetos e eles podem ser passados como parâmetros para outras funções (chamadas de callbacks) e podem ser chamados na conclusão de uma tarefa específica.Isso é exatamente o que node.js faz no servidor.Você pode encontrar mais informações sobre programação orientada a eventos e bloqueio de entrada / saída, no contexto do nó aqui

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *