Tenho passado retornos de chamada ou apenas acionado as funções de outras funções nos meus programas para que as coisas aconteçam 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 li sobre muitas estratégias diferentes de programação, e uma que eu entendo ser poderosa, mas que ainda não pratiquei, é baseada em eventos (acho que um método que li sobre foi chamado "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);
Gostaria de entender os pontos fortes e fracos objetivos da programação baseada em eventos, em vez de chamar todas as suas funções de outras funções. Em quais situações de programação a programação baseada em eventos faz sentido?
event-programming
Viziionary
fonte
fonte
$(document).bind('snow', shovelShow)
. Não há necessidade de envolvê-lo em uma função anônima.Respostas:
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 funções de expedidor e manipulador de eventos (ou assinantes ). O expedidor fornece uma API para conectar manipuladores até eventos (jQuery
bind
) e um método para publicar um evento para seus assinantes (trigger
no jQuery). Quando você está falando sobre eventos de IO ou UI, também costuma haver um loop de eventos , que detecta novos eventos como cliques do mouse e os passa para o expedidor. No JS-land, o dispatcher e o loop de eventos são fornecidos pelo navegador.Para código que interage diretamente com o usuário - respondendo a pressionamentos de tecla e cliques - a programação orientada a eventos (ou uma variação dela, como a programação reativa funcional ) é quase inevitável. Você, o programador, não tem idéia de quando ou onde o usuário clicará, portanto, cabe à estrutura ou ao navegador da GUI detectar a ação do usuário em seu loop de eventos e notificar seu código. Esse tipo de infraestrutura também é usado em aplicativos de rede (cf NodeJS).
Seu exemplo, no qual você gera um evento em seu código, em vez de chamar uma função diretamente, tem algumas vantagens mais interessantes, as quais discutirei abaixo. A principal diferença é que o editor de um evento (
makeItSnow
) não especifica o destinatário da chamada; que está conectado em outro lugar (na chamada parabind
no seu exemplo). Isso é chamado de acenda e esqueça :makeItSnow
anuncia ao mundo que está nevando, mas não se importa com quem está ouvindo, o que acontece depois ou quando acontece - simplesmente transmite a mensagem e tira o pó das mãos.Portanto, a abordagem orientada a eventos desacopla o remetente da mensagem do destinatário. Uma vantagem que isso oferece é que um determinado evento pode ter vários manipuladores. Você pode vincular uma
gritRoads
função ao seu evento de neve sem afetar oshovelSnow
manipulador existente . Você tem flexibilidade na maneira como seu aplicativo é conectado; Para desativar um comportamento, basta remover abind
chamada, em vez de procurar o código para encontrar todas as instâncias do comportamento.Outra vantagem da programação orientada a eventos é que ela oferece um local para colocar preocupações transversais. O distribuidor de eventos desempenha o papel de Mediador , e algumas bibliotecas (como o Brighter ) utilizam um pipeline para que você possa conectar facilmente requisitos genéricos, como log ou qualidade de serviço.
Divulgação completa: O Brighter é desenvolvido na Huddle, onde trabalho.
Uma terceira vantagem de dissociar o remetente de um evento do receptor é que ele oferece flexibilidade quando você lida com o evento. Você pode processar cada tipo de evento em seu próprio encadeamento (se o seu expedidor de eventos o suportar) ou pode colocar eventos gerados em um intermediário de mensagens como o RabbitMQ e manipulá-los com um processo assíncrono ou até processá-los 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 idéia 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 um exemplo bastante diferente de estilo orientado a eventos, consulte o design orientado a domínio , onde os eventos de domínio são usados para ajudar a manter agregados separados. Por exemplo, considere uma loja online que recomende produtos com base no seu histórico de compras. A
Customer
precisa ter seu histórico de compras atualizado quando aShoppingCart
é paga. OShoppingCart
agregado pode notificar o eventoCustomer
criando umCheckoutCompleted
evento; oCustomer
seria atualizado em uma transação separada em resposta ao evento.A principal desvantagem desse modelo orientado a eventos é a indireção. Agora é mais difícil encontrar o código que lida com o evento porque você não pode simplesmente navegar para ele usando seu IDE; você precisa descobrir onde o evento está vinculado na configuração e esperar que você tenha encontrado todos os manipuladores. Há mais coisas para manter em sua mente a qualquer momento. As convenções de estilo de código podem ajudar aqui (por exemplo, colocar todas as chamadas
bind
em um arquivo). Por uma questão de sanidade, é importante usar apenas um distribuidor de eventos e usá-lo 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 as versões do software!
Em certas circunstâncias, o desempenho pode ser uma preocupação. Ao processar uma mensagem, o expedidor deve:
Isso é certamente mais lento que uma chamada de função normal, que envolve apenas empurrar um novo quadro na pilha. No entanto, a flexibilidade oferecida por uma arquitetura orientada a eventos facilita muito o isolamento e a otimização do 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 duro é tratado em segundo plano. De qualquer forma, se você estiver interagindo com o banco de dados ou desenhando coisas na tela, os custos de IO reduzirão totalmente os custos de processamento de uma mensagem. É um caso de evitar a otimização prematura.
Em resumo, os eventos são uma ótima maneira de criar software com pouca acoplagem, mas não são isentos de custos. Seria um erro, por exemplo, substituir cada chamada de função no seu aplicativo por um evento. Use eventos para criar divisões arquitetônicas significativas.
fonte
A programação baseada em eventos é usada quando o programa não controla a sequência de eventos que ele 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, apenas o faz. É não baseada em eventos.
Um processador de texto fica lá e aguarda o usuário começar a digitar. As teclas pressionadas 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, ele deve ser orientado a eventos.
A maioria dos programas da GUI é orientada a eventos porque eles são criados com base na interação do usuário. No entanto, os programas baseados em eventos não se limitam às GUIs, que é simplesmente o exemplo mais familiar para a maioria das pessoas. Os servidores Web esperam que os clientes se conectem e sigam um idioma semelhante. Os processos em segundo plano no seu computador também podem responder a eventos. Por exemplo, um antivírus sob demanda pode receber um evento do sistema operacional referente a um arquivo recém-criado ou atualizado e, em seguida, verificar esse arquivo em busca de vírus.
fonte
Em um aplicativo baseado em evento, o conceito de ouvintes de eventos oferece a capacidade de escrever ainda mais aplicativos com acoplamento fraco .
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 do evento fazerem seu trabalho. Tudo funcionará bem, mesmo que o módulo acionador nem saiba quem está ouvindo esse evento em particular ou o que deve acontecer a seguir.fonte
Uma analogia simples que eu gostaria de acrescentar que me ajudou:
Pense nos componentes (ou objetos) do seu aplicativo como um grande grupo de amigos do Facebook.
Quando um de seus amigos quer lhe contar uma coisa, eles podem ligar diretamente para você ou publicá-la no mural do Facebook. Quando eles publicam no Facebook, qualquer pessoa pode vê-lo e reagir, mas muitas pessoas não. Às vezes, é algo importante que as pessoas provavelmente precisam reagir a ela, como "Estamos tendo um bebê!" ou "A banda mais ou menos está fazendo um show surpresa no bar Drunkin 'Clam!". No último caso, os outros amigos provavelmente precisarão reagir a isso, principalmente se estiverem interessados nessa banda.
Se seu amigo quiser manter um segredo entre você e ele, provavelmente não o publicará no mural do Facebook, ligará diretamente para você e lhe contará. Imagine um cenário em que você diz a uma garota que gosta de encontrá-la em um restaurante para um encontro. Em vez de ligar diretamente para ela e perguntar, você a publica no mural do Facebook para que todos os seus amigos vejam. Isso funciona, mas se você tem uma ex ciumenta, ela pode ver isso e aparecer no restaurante para estragar o seu dia.
Ao decidir se deve ou não criar ouvintes de eventos para implementar algo, pense nessa analogia. Esse componente precisa divulgar seus negócios para qualquer um ver? Ou eles precisam ligar para alguém diretamente? As coisas podem ficar confusas com bastante facilidade, por isso tome cuidado.
fonte
Essa analogia a seguir pode ajudá-lo a entender a programação de E / S orientada a eventos desenhando uma linha paralela à de espera na recepção do médico.
Bloquear E / S é como, se você estiver na fila, a recepcionista pede a um cara na sua frente para preencher o formulário e ela espera até que ele termine. Você tem que esperar sua vez até que o cara termine sua forma, isso está bloqueando.
Se um cara leva 3 minutos para preencher, o 10º cara tem que esperar até 30 minutos. Agora, para reduzir esse 10º tempo de espera, a solução seria aumentar o número de recepcionistas, o que é caro. É o que acontece nos servidores da web tradicionais. Se você solicitar informações do usuário, a solicitação subsequente de outros usuários deverá aguardar a conclusão da operação atual, buscando no Banco de Dados. 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 um encadeamento (equivalente ao número crescente de recepcionistas) para cada solicitação única, ou seja, basicamente cria uma cópia do servidor para cada solicitação, o que representa um custo caro do consumo de CPU, pois cada solicitação precisará de um sistema operacional. fio. Para ampliar o aplicativo,
Orientado a Eventos : A outra abordagem para aumentar o "tempo de resposta" da fila é optar pela abordagem orientada a eventos, onde o pessoal da fila será entregue ao formulário, solicitado a preencher e retornar após a conclusão. Portanto, a recepcionista sempre pode atender a solicitação. É exatamente isso que o javascript tem feito desde o início. No navegador, o javascript responderia ao evento de clique do usuário, rolagem, furto ou busca no banco de dados e assim por diante. Isso é possível no javascript inerentemente, porque o javascript trata as funções como objetos de primeira classe e pode ser passado como parâmetro para outras funções (chamadas de retorno de chamada) e pode ser chamado na conclusão de uma tarefa específica. É exatamente isso que o node.js faz no servidor. Você pode encontrar mais informações sobre programação orientada a eventos e bloqueio de E / S, no contexto do nó aqui
fonte