freeCodeCamp/guide/portuguese/nodejs/event-emitters/index.md

183 lines
8.4 KiB
Markdown
Raw Normal View History

---
title: Event Emitters
localeTitle: Emissores de Eventos
---
## Eventos e Transmissões
Tradicionalmente, em um servidor da Web, processar um dado na forma de um arquivo lendo e gravando consome muito mais memória, pois esses métodos de processamento precisam carregar o arquivo toda vez que ele precisar ler ou gravar esse arquivo. Isso é considerado um desperdício de recursos. Pense nisso, em termos de escalabilidade e Big Data, se estamos desperdiçando recursos, vamos nos comprometer muito. A natureza assíncrona do Node.js fornece duas opções adequadas para trabalharmos e fornecer um fluxo de dados que consome menos recursos, pois o Node.js é baseado em um modelo assíncrono sem bloqueio. Eles estão emitindo eventos e fluxos. Nesta seção, vamos dar uma olhada em ambos.
## Classe EventEmitter
EventEmitters são uma das principais idéias por trás da arquitetura de programação orientada a eventos ou programação assíncrona em Node.js. Um EventEmitter é um objeto e, no Node.js, qualquer objeto que emite um evento é uma instância da classe EventEmitter. O que é um evento? Todas as ações executadas pelo programa Node.js, como iniciar o servidor da Web e fechar o encerramento do programa quando não há solicitações a serem atendidas, são consideradas como dois eventos separados.
Para acessar a classe EventEmitter em um programa Node.js, você precisa exigir o módulo de `events` da API Node.js. Para criar o objeto, criamos uma instância da classe EventEmitter chamando sua função construtora.
```js
const events = require('events');
const eventEmitter = new events.EventEmitter();
```
Ou você pode exigir acesso direto à subclasse EventEmitter da seguinte forma:
```js
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();
```
Uma classe EventEmitter fornece vários métodos predefinidos para trabalhar com eventos. Estes métodos são `.on` , `.emit` e `.error` . Emitir um evento de uma função pode ser feito acionando uma função de retorno de chamada que pode ser acessada por qualquer outra função JavaScript. Isso é como transmitir.
A capacidade de acionar um evento pode ser feita seguindo a sintaxe:
```js
eventEmitter.emit(eventName, optionalData);
```
E a capacidade de anexar uma função de ouvinte e definir o nome de um evento específico é feita por `.on` .
```js
eventEmitter.emit(eventName, callback);
```
Vamos imitar as novas funções que acabamos de aprender com um exemplo. Crie um novo arquivo chamado `eventemitter.js` e cole o seguinte código:
```js
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();
const callback = () => {
console.log('callback runs');
};
eventEmitter.on('invoke', callback);
eventEmitter.emit('invoke');
eventEmitter.emit('invoke');
```
Agora execute o exemplo acima usando o comando `node` e você deve obter a seguinte saída.
```shell
callback runs
callback runs
```
Começamos criando uma instância eventEmitter através do qual tenha acesso aos `.on` o método. O `.on` método adiciona o evento, definindo o nome `invoke` que usamos mais tarde na `.emit` chamar acionar a função de retorno de chamada associado a ele.
Há outra função que a classe EventEmitter fornece, chamada `.once` . Esse método invoca apenas a função de retorno de chamada associada a um evento pela primeira vez quando um evento é emitido. Considere o exemplo abaixo.
```js
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();
const callback = () => {
console.log('callback runs');
};
eventEmitter.once('invoke', callback);
eventEmitter.emit('invoke');
eventEmitter.emit('invoke');
```
Saída
```shell
callback runs
```
`.once` manter as faixas de eventos de quando elas são acionadas e quantas vezes elas são acionadas, ao contrário do método `.on` , que não acompanha essa situação. Esta é uma diferença importante entre os dois.
## Compreender fluxos
O Node.js fornece outra maneira de trabalhar com dados, em vez de consumir uma grande quantidade de recursos de memória e torná-lo econômico. Isso que fluxos fazem. Basicamente, os fluxos permitem que você leia dados da única fonte e os coloque no destino. Os fluxos processam os dados em blocos em vez de todos de uma só vez, tornando-os adequados para trabalhar com grandes conjuntos de dados. Muitos módulos Node.js internos usam streams sob o capô. Por exemplo, solicitação e resposta HTTP, sockets TCP, zlib, crypto, fs lêem e gravam fluxos, etc.
### Tipo de fluxos
No Node.js, existem quatro tipos de fluxos:
* Legível
* Gravável
* Duplex
* Transformar
Os mais comuns são fluxos legíveis e graváveis. Os fluxos legíveis são usados para ler os dados da origem e os fluxos graváveis são usados para executar a operação de gravação desses dados no destino. Fluxos duplex podem ser usados para executar operações de leitura e gravação. Transform é um superconjunto de fluxos Duplex, com a única diferença é que os dados podem ser modificados durante a leitura ou gravação.
### Tipo de eventos de fluxo
Todos esses tipos de fluxo são instâncias da classe EventEmitter, o que significa que eles emitem eventos de leitura e gravação. Cada tipo de fluxo pode emitir os seguintes eventos.
* data: esse evento é acionado quando os dados estão disponíveis para leitura pelo fluxo legível
* error: Este evento é acionado quando há um erro ao ler ou gravar os dados
* end: este evento é acionado quando não há dados para ler
## Correntes legíveis
Um fluxo legível permite ler os dados da fonte. Esta fonte pode ser qualquer coisa, desde um buffer, um arquivo, etc. Primeiro, crie um arquivo de texto simples a partir do qual vamos ler os dados usando o fluxo.
```text
I am Text file that contains data.
```
Agora, crie um novo arquivo chamado read.js, que implementará a funcionalidade de leitura de dados desse arquivo de texto usando um fluxo legível.
```js
const fs = require('fs');
const readableStream = fs.createReadStream('abc.txt');
let data = '';
readableStream.on('data', function(chunk) {
data += chunk;
});
readableStream.on('end', function() {
console.log(data);
});
```
Se você executar o programa acima, você receberá a seguinte saída:
```shell
$ node test.js
I am Text file that contains data.
```
Qual é o que escrevemos dentro do arquivo de texto. Para ler dados usando o fluxo, usamos uma função chamada `createReadStream()` do módulo do sistema de arquivos `fs` .
Quando não há dados para ler pelo fluxo legível, ele automaticamente termina a função de retorno de chamada. O método `.on` é o que aprendemos na seção anterior da classe EventEmitter. Isso significa que os streams usam a classe EventEmitter nos bastidores.
## Stream gravável
Os fluxos graváveis são usados para gravar ou inserir ou anexar dados a um destino. Como fluxos legíveis, eles também são fornecidos pelo módulo `fs` . Crie um novo arquivo chamado `wrtte.js` no qual usará um fluxo legível para ler dados da origem e gravá-lo em um destino criando um novo arquivo `.txt` .
```js
const fs = require('fs');
const readableStream = fs.createReadStream('./abc.txt');
const writeableStream = fs.createWriteStream('./dest.txt');
let data = '';
readableStream.on('data', function(chunk) {
writeableStream.write(chunk);
});
```
Quando você executa este programa, um novo arquivo será criado pelo fluxo gravável desde que tenha acesso ao módulo do sistema de arquivos. O fluxo gravável usa o método `.write()` para produzir os dados no destino. No exemplo acima, estamos criando um novo arquivo chamado `dest.txt` que conterá os mesmos dados de `abc.txt` .
## Tubulação
Piping é um mecanismo pelo qual você pode ler dados a partir da fonte e escrevê-lo para o destino sem escrever muito código como fizemos acima e não usar `.on` ou `.write` métodos.
Se estamos a escrever acima exemplo usando pipe, vamos escrever como abaixo:
```js
const fs = require('fs');
const readableStream = fs.createReadStream('./abc.txt');
const writeableStream = fs.createWriteStream('./dest.txt');
readableStream.pipe(writeableStream);
```
Observe quantas linhas de código foram removidas. Além disso, agora precisamos apenas dos caminhos de arquivos de origem e de destino e, para ler e gravar dados, estamos usando o método `.pipe()` .