Introdução: eventos do sistema vs. eventos personalizados

Eventos em Node.js são ações que ocorrem em nosso aplicativo que podemos responder para. Existem dois tipos diferentes de eventos em Node.js, ambos os quais abordaremos neste artigo.

1. Eventos do sistema : os eventos do sistema ocorrem no lado C ++ do núcleo do Node.js e são gerenciados por uma biblioteca C usada no Node.js chamada libuv .

A biblioteca libuv lida com eventos de nível inferior que acontecem dentro do sistema do computador, essencialmente, eventos de baixo nível que vêm do sistema operacional, como o recebimento de dados da internet, leitura finalizada um arquivo e assim por diante.

Como o fluxo de um programa Node.js é determinado por eventos (programação orientada a eventos), todas as solicitações de E/S acabariam por gerar um evento de conclusão/falha .

Observação lateral: o JavaScript não tem recursos integrados para lidar com eventos do sistema.

2. Eventos personalizados : eventos personalizados ocorrem dentro do núcleo do JavaScript em Node.js. Esses eventos são tratados por uma classe Node.js chamada EventEmitter .

O EventEmitter é uma classe JavaScript em Node.js implementada para lidar com eventos personalizados porque o JavaScript não tem nenhum recurso integrado para lidar com eventos de outra forma.

Freqüentemente, quando um evento ocorre em libuv , libuv gera eventos JavaScript personalizados para que possam ser facilmente manipulados. Consequentemente, os eventos do Node.js podem ser vistos como uma única entidade, embora sejam, na verdade, dois tipos diferentes de eventos.

Neste artigo, nosso foco será em eventos JavaScript personalizados e no emissor de eventos .

O que são emissores de evento?

Node.js usa o padrão de programação orientado a eventos conforme observado acima. Este padrão de design é para produzir e consumir eventos e é predominantemente usado no frontend ( navegador ). As ações do usuário, como um botão clique ou um pressionamento de tecla , geram um evento.

Esses eventos têm funções associadas chamadas ouvintes, que são chamados para lidar com seus eventos correspondentes quando são emitidos.

O padrão orientado a eventos tem dois componentes principais:

  1. Um manipulador de eventos (ouvinte). Esta é a função que seria chamada quando o evento fosse emitido. Mais de um ouvinte pode estar ouvindo um evento. Quando o evento é emitido, esses ouvintes são chamados de forma síncrona.
  2. Um loop principal que escuta eventos e chama os ouvintes associados para lidar com esse evento.

O Node.js traz a programação orientada a eventos para o back-end por meio do Classe Emissor de evento . A classe Event Emitter é uma parte do módulo Node.js principal events . Ele fornece uma maneira de emitir e manipular eventos e expõe-entre muitos outros-os métodos on e emit .

Neste artigo, construiremos um emissor de evento personalizado usando os princípios básicos que alimentam os Emissores de evento do Node.js para que possamos entender melhor os emissores de evento do Node.js.

O código a seguir mostra como emitir e tratar eventos usando o objeto Event Emitter .

 const EventEmitter=require ('eventos');
const eventEmitter=new EventEmitter (); eventEmitter.on ('greet', ()=> { console.log ('Olá, mundo!');
}); eventEmitter.emit ('saudar');

No código acima, o método eventEmitter.on é usado para registrar ouvintes que manipulam um evento, enquanto o método eventEmitter.emit é usado para emitir eventos.

Ao emitir o evento greet acima, a função que escuta o evento greet é chamada e Hello world! é registrado no console.

Outros métodos expostos pelos objetos Emissor de evento são:

  1. eventEmitter.once () : adiciona um ouvinte único
  2. eventEmitter.off () : este é um alias para eventEmitter.removeListener () . Ele remove um ouvinte de evento de um evento
  3. eventEmitter.listnersCount () : retorna o número de ouvintes escutando um evento

No Node.js, existem outros objetos que podem emitir eventos. No entanto, todos os objetos que emitem eventos são uma instância da classe Emissor de eventos . Para entender melhor o Emissor de evento , vamos construir o nosso próprio.

O padrão geral para um emissor de evento personalizado

A ideia geral de um Emissor de evento é ter um objeto de evento cujas chaves atuam como eventos personalizados e os valores correspondentes seriam matrizes de ouvintes que são chamados de forma síncrona quando o evento é emitido.

Considere o código abaixo:

 const GreetHandlers=[ ()=> {console.log ("Olá, mundo!"), ()=> {console.log ("Olá, desenvolvedor!"), ()=> {console.log ("Hello From LogRocket!"}
]; eventos const={ "saudar": GreetHandlers
}

Aqui, o objeto events tem uma propriedade: "greet". Todo nome de propriedade deste objeto é considerado um evento único, significando que a propriedade "greet" é um evento. O valor da propriedade (evento) "greet" é o array GreetHandlers . Este é um array contendo funções (ou ouvintes) que seriam chamados de forma síncrona quando o evento "greet" ocorrer.

Para chamar essas funções de forma síncrona, percorremos a matriz e invocamos cada função, conforme visto a seguir:

 GreetHandlers.forEach (listener=> { ouvinte();
}); //Resultado:
//"Olá Mundo!"
//"Olá Desenvolvedor!"
//"Hello From LogRocket!"

Nosso exemplo acima oferece uma visão geral simplificada do padrão usado no Event Emitter do Node.js. Usaremos o mesmo padrão conforme construímos nosso próprio Emissor de evento na próxima seção.

Construindo um emissor de evento personalizado

Embora o Event Emitter do Node.js seja uma classe JavaScript, iremos construir a nossa própria usando um construtor de função para que possamos entender o que está acontecendo em segundo plano.

As classes em JavaScript fornecem uma sintaxe nova e fácil para trabalhar com os herança prototípica . Como as classes em JavaScript são um açúcar sintático para o padrão prototípico, muitas coisas ocorrem nos bastidores que estão ocultas de nós.

Para construir nosso Emissor de evento personalizado, siga as etapas abaixo:

  1. Crie o construtor da função Emissor de evento . Deve ter uma propriedade (o objeto de evento).
 function Emitter () { this.events={};
} 

O objeto events acima serviria como o objeto principal que contém todos os eventos personalizados.

Cada chave e valor deste objeto corresponde a um evento e sua matriz de ouvintes.

 function Emitter () { this.events={ "saudar": [ ()=> {}, ()=> {}, ()=> {}, ], "falar": [ ()=> {}, ()=> {}, ()=> {}, ]
}
  1. Adicione métodos ao protótipo do Emissor de evento .

O JavaScript orientado a objetos (OOP) nos oferece uma maneira limpa de compartilhar propriedades e métodos em nosso aplicativo. Isso ocorre porque o padrão prototípico permite que objetos acessem propriedades na cadeia de protótipo, o que significa que um objeto pode acessar propriedades em seu protótipo, no protótipo de seu protótipo e além.

O mecanismo JavaScript primeiro procura um método ou propriedade no protótipo de um objeto se ele estiver ausente no objeto. Se não o encontrar no protótipo desse objeto, ele continua sua busca ao longo da cadeia de protótipos. Este padrão de herança é conhecido como herança prototípica .

Por causa da herança prototípica do JavaScript, quando adicionamos propriedades e métodos ao protótipo de um objeto, todas as instâncias desse objeto teriam acesso a eles.

Veja aqui no código abaixo, onde adicionamos o método on :

 Emitter.prototype.on=function (type, listener) { //verifique se o ouvinte é uma função e lance um erro se não for if (typeof listener!=="function") { lançar um novo erro ("O ouvinte deve ser uma função!") } //cria a propriedade do ouvinte de evento (array) se ela não existir. this.events [type]=this.events [type] || []; //adiciona listners ao array de eventos. this.events [type].push (ouvinte);
}

O código acima adiciona a função on ao protótipo do objeto Emitter , que permite que todas as instâncias do objeto Emitter herdem isso método.

O método on leva dois argumentos, a saber: type e listener (uma função).

Primeiro, o método on verifica se o listener é uma função. Se não for, ele gerará um erro conforme mostrado abaixo:

 if (typeof listener!=="function") { lançar um novo erro ("O ouvinte deve ser uma função!")
}

Além disso, o método on verifica se o tipo de evento está presente no objeto events (como uma chave). Se não estiver presente, ele adiciona um evento (como uma chave) ao objeto events e define seu valor para uma matriz vazia. Finalmente, ele adiciona ouvintes à matriz de evento correspondente: this.events [type].push (listener); .

Agora vamos adicionar o método emit :

 Emitter.prototype.emit=função (tipo) { if (this.events [type]) {//verifica se o evento é uma propriedade no Emitter this.events [type].forEach (function (listener) { //faz um loop pela matriz de eventos e invoca todos os ouvintes dentro dela. ouvinte (); }) } } //se usado como um módulo de nó. Exporta este construtor de função
modules.exports=Emissor;
//Isso o torna disponível a partir de require ()
//para que possamos fazer quantas instâncias quisermos.

O código acima adiciona o método emit ao protótipo Emitters . Ele simplesmente verifica se o tipo de evento está presente (como uma chave) no objeto events . Se estiver presente, ele invoca todos os ouvintes correspondentes, conforme já discutido acima.

O código this.events [type] retorna o valor da propriedade do evento correspondente, que é uma matriz contendo ouvintes.

Consequentemente, o código a seguir percorre a matriz e invoca todos os seus ouvintes de forma síncrona.

 this.events [type].forEach (function (listener) { //faz um loop por essa matriz de eventos e invoca todos os ouvintes dentro dela. ouvinte ();
})

Para usar nosso Emissor de evento , teríamos que emitir um evento manualmente.

//se usado em um ambiente Node.js, requer o módulo conforme visto abaixo.
const Emitter=require ('./emissor'); const eventEmitter=new Emitter (); eventEmitter.on ('greet', ()=> { console.log ("Olá, mundo!");
}); eventEmitter.on ('greet', ()=> { console.log ("Hello from LogRocket!");
}); eventEmitter.emit ("saudação");//emite um evento manualmente

No código acima, primeiro exigimos e criamos uma instância do módulo Emitter usando este:

 const Emitter=require ('./emitter'); const eventEmitter=new Emitter ();

Em seguida, atribuímos ouvintes ao evento "greet" usando o método on .

 eventEmitter.on ('greet', ()=> { console.log ("Olá, mundo!");
}); eventEmitter.on ('greet', ()=> { console.log ("Hello from LogRocket!");
});

Finalmente, emitimos manualmente o evento greet usando esta linha:

 emtr.emit ("saudar");

Resultados do código

A imagem acima mostra o resultado da execução de nosso código. Obtenha o código completo em JavaScript simples.

Adicionando mais métodos de evento

O método addListener

É importante observar que o método on é na verdade um alias para o método addListener no Event Emitter do Node.js. Portanto, precisamos refatorar a implementação.

 Emitter.prototype.addListener=function (type, listener) { //verifique se o ouvinte é uma função e lance um erro se não for if (typeof listener!=="function") { lance new Error ("O ouvinte deve ser uma função!"); } //cria a propriedade do ouvinte de evento (array) se ela não existir. this.events [type]=this.events [type] || []; //adiciona listners ao array de eventos. this.events [type].push (ouvinte);
};
Emitter.prototype.on=function (type, listener) { retornar this.addListener (tipo, ouvinte);
};

O código acima ainda funciona, mas nesta versão, tanto o método addListener quanto o método on fazem a mesma coisa.

O método listenersCount

Também existe o método listenersCount . Isso retorna o número total de funções (ouvintes) que estão ouvindo um determinado evento. Vamos implementar isso abaixo:

 Emitter.prototype.listenerCount=function (type) { deixe listnersCount=0; deixe listeners=this.events [type] || []; listnersCount=listners.length; console.log ("ouvintes listnersCount", listnersCount); return listnersCount;
};

Aqui, dizemos ao armazenamento simples a matriz de ouvintes para o evento especificado na variável de ouvintes usando:

 let listeners=this.events [type] || [];

Se o evento não for encontrado, um array vazio é armazenado. Em seguida, retornamos o comprimento da variável de ouvinte .

O Event Emitter no Node.js segue a mesma ideia, mas tem muitos recursos extras. Acabamos de construir uma versão simples.

Você pode brincar com o código final em JavaScript simples aqui.

Conclusão

O emissor de evento é um bloco de construção fundamental de muitas partes do núcleo do JavaScript Node.js.

Todos os objetos Node.js (como streams e o módulo HTTP ) que emitem eventos são instâncias da classe Event Emitter .

É um objeto importante no Node.js que é definido e exposto pelo módulo de eventos .

Por meio da classe Event Emitter , o Node.js traz a programação orientada a eventos para o lado do servidor.

Espero que ao construir nosso pequeno Emissor de evento inventado, você tenha sido capaz de aprender mais sobre a classe Emissor de evento do Node.js.

A postagem Construindo emissores de eventos Node.js personalizados apareceu primeiro no LogRocket Blog .

Source link