---
title: Event Emitters
localeTitle: Излучатели событий
---
## События и потоки

Традиционно на веб-сервере для обработки данных в виде файла путем чтения и записи потребляется намного больше памяти, поскольку эти методы обработки должны загружать файл каждый раз, когда он должен читать или записывать этот файл. Это считается пустой тратой ресурсов. Подумайте об этом, имея в виду масштабируемость и большие данные, если мы тратим ресурсы, мы собираемся пойти на компромисс. Асинхронный характер Node.js предоставляет нам два подходящих варианта для работы с потоком данных, который потребляет меньше ресурсов, поскольку Node.js основан на неблокирующей асинхронной модели. Они излучают события и потоки. В этом разделе мы рассмотрим их обоих.

## Класс EventEmitter

EventEmitters - одна из основных идей архитектуры архитектуры, управляемой событиями, или асинхронного программирования в Node.js. EventEmitter - это объект, а в Node.js любой объект, который испускает событие, является экземпляром класса EventEmitter. Что такое событие? Каждое действие, выполняемое программой Node.js, например, инициирование веб-сервера и закрытие завершающей программы, когда нет запроса, оставшегося на выполнение, рассматриваются как два отдельных события.

Чтобы получить доступ к классу EventEmitter в программе Node.js, вам потребуется модуль `events` из API Node.js. Чтобы создать объект, мы затем создаем экземпляр класса EventEmitter, вызывая его конструктор.

```js
const events = require('events'); 
 
 const eventEmitter = new events.EventEmitter(); 
```

Или вы можете напрямую потребовать доступ к подклассу EventEmitter следующим образом:

```js
const EventEmitter = require('events'); 
 
 const eventEmitter = new EventEmitter(); 
```

Класс EventEmitter предоставляет различные предопределенные методы работы с событиями. Эти методы: `.on` , `.emit` и `.error` . Выпуск события из функции может быть выполнен с помощью функции обратного вызова, к которой может обращаться любая другая функция JavaScript. Это похоже на вещание.

Возможность запуска события может быть выполнена с помощью следующего синтаксиса:

```js
eventEmitter.emit(eventName, optionalData); 
```

А возможность присоединения функции слушателя и определения имени конкретного события выполняется с помощью `.on` .

```js
eventEmitter.emit(eventName, callback); 
```

Мы будем подражать новым функциям, которые мы только что узнали, с примером. Создайте новый файл с именем `eventemitter.js` и вставьте следующий код:

```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'); 
```

Теперь запустите приведенный выше пример, используя команду `node` и вы должны получить следующий вывод.

```shell
callback runs 
 callback runs 
```

Мы начинаем с создания экземпляра eventEmitter, через который мы получаем доступ к `.on` метод. Метод `.on` добавляет событие, определяя имя `invoke` которое мы используем позже в `.emit` чтобы вызвать функцию связанного с ним функции обратного вызова.

Существует еще одна функция, предоставляемая классом `.once` которая называется `.once` . Этот метод вызывает только функцию обратного вызова, связанную с событием в первый раз при испускании события. Рассмотрим приведенный ниже пример.

```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'); 
```

Вывод

```shell
callback runs 
```

`.once` отслеживать события событий, когда они срабатывают, и сколько раз они запускаются в отличие от метода `.on` который не отслеживает это. Это основное различие между ними.

## Понимание потоков

Node.js предоставляет другой способ работы с данными вместо того, чтобы потреблять большой объем ресурсов памяти и сделать его экономически эффективным. Это то, что делают потоки. По сути, потоки позволяют читать данные из одного источника и помещать их в пункт назначения. Потоки обрабатывают данные в кусках, а не одновременно, делая их пригодными для работы с большими наборами данных. Многие встроенные модули Node.js используют потоки под капотом. Например, HTTP-запрос и ответ, TCP-сокеты, zlib, crypto, fs чтение и запись потоков и т. Д.

### Тип потоков

В Node.js существует четыре типа потоков:

*   Удобочитаемый
*   Writable
*   дуплексный
*   преобразование

Наиболее распространенными из них являются Readable и Writable streams. Считываемые потоки используются для чтения данных из источника, а записываемые потоки используются для выполнения операции записи этих данных в пункт назначения. Дуплексные потоки могут использоваться для выполнения операций чтения и записи. Transform - это надстройка дуплексных потоков, с той лишь разницей, что при этом данные могут быть изменены при чтении или написании.

### Тип потока событий

Все эти типы потоков являются экземплярами класса EventEmitter, что означает, что они испускают события чтения и записи. Каждый тип потока может выделять следующие события.

*   data: это событие запускается, когда данные доступны для чтения считываемым потоком
*   error: это событие запускается, когда появляется ошибка при чтении или записи данных
*   end: Это событие активируется, когда нет данных, оставшихся для чтения

## Чтение потоков

Читаемый поток позволяет читать данные из источника. Этот источник может быть любым из буфера, файла и т. Д. Сначала создайте файл простого текстового файла, из которого мы будем считывать данные с помощью потока.

```text
I am Text file that contains data. 
```

Теперь создайте новый файл read.js, который будет реализовывать функциональность чтения данных из этого текстового файла с помощью читаемого потока.

```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); 
 }); 
```

Если вы запустите указанную выше программу, вы получите следующий результат:

```shell
 $ node test.js 
 I am Text file that contains data. 
```

Это то, что мы написали внутри текстового файла. Для чтения данных с использованием потока мы используем функцию `createReadStream()` модуля файловой системы `fs` .

Когда нет данных, которые можно прочитать считываемым потоком, он автоматически завершает функцию обратного вызова. Метод `.on` - это то, что мы узнали в предыдущем разделе класса EventEmitter. Это означает, что потоки используют класс EventEmitter за кулисами.

## Считываемый поток

Записываемые потоки используются для записи или вставки или добавления данных в пункт назначения. Подобно читаемым потокам, они также предоставляются модулем `fs` . Создайте новый файл `wrtte.js` в котором будет использоваться читаемый поток для чтения данных из источника и записи его в пункт назначения, создав новый `.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); 
 }); 
```

Когда вы запустите эту программу, новый файл будет создан потоком записи, так как он имеет доступ к модулю файловой системы. Writable stream использует `.write()` для вывода данных по месту назначения. В приведенном выше примере мы создаем новый файл с именем `dest.txt` который будет содержать те же данные, что и `abc.txt` .

## кант

Протокол - это механизм, с помощью которого вы можете считывать данные из источника и записывать его в пункт назначения, не пиши столько кода, как мы делали выше, и он не использует `.on` или `.write` .

Если мы напишем выше пример с использованием pipe, мы будем писать, как показано ниже:

```js
const fs = require('fs'); 
 const readableStream = fs.createReadStream('./abc.txt'); 
 const writeableStream = fs.createWriteStream('./dest.txt'); 
 
 readableStream.pipe(writeableStream); 
```

Обратите внимание, сколько строк кода мы удалили. Кроме того, нам нужны только пути к исходному и целевому файлам, а также для чтения и записи данных, которые мы используем `.pipe()` .