Автор оригинала: Janith Kasun.
Вступление
В этом руководстве мы посмотрим на родной узел Eventemitter
класс. Вы узнаете о событиях, что вы можете сделать с Дедимотер
И как использовать события в вашем приложении.
Мы также охватим, какие другие родные модули простираются от Eventemitter
Класс и некоторые примеры, чтобы понять, что происходит за кулисами.
Так что в двух словах мы охватим почти все, что вам нужно знать о Eventemitter
класс.
Мы будем использовать некоторые основные функции ES6, такие как классы JavaScript и функции стрелки в этом руководстве. Это полезно, но не обязательно, если у вас есть некоторые предыдущие знания синтаксиса ES6.
Что такое событие?
В целом программное обеспечение парадигма вращается вокруг событий и их использование. Архитектура, управляемая событием относительно распространена в наши дни, и приложения, ориентированные на события, и реагируют на разные виды событий.
Мы можем сказать, что ядро Node.js частично приводят к событиям, так как многие родные модули, такие как файловая система ( FS
), и поток
Модуль написан как Eventemitter
сами по себе.
В программировании, ориентированном с событиями, событие является результатом одного или нескольких действий. Это может быть действием пользователя или периодический выход из датчика, например.
Вы можете просмотреть программы, ориентированные на мероприятия в качестве моделей публикации-подписки, где издатель запускает события, а подписчики слушают их и действуют соответствующим образом.
Например, давайте предположим, что у нас есть сервер изображений, в котором пользователи могут загружать изображения. В программировании, ориентированном на события, действие, такое как загрузка изображения, выделяет событие. Использовать его, также будет 1..n
подписчики на это событие.
Как только событие загрузки будет запущено, абонент может реагировать на него, отправив электронное письмо администратору веб-сайта, позволяя им знать, что пользователь загрузил фотографию. Другой подписчик может собирать информацию о действии и сохранять их в базе данных.
Эти события, как правило, независимы друг от друга, хотя они также могут зависеть.
Что такое события?
Eventemitter
Класс – это встроенный класс, который находится в События
модуль. Согласно документации:
Большая часть Node.js Core API построена вокруг идиоматической асинхронной архитектуре, приводимой к мероприятиям, в которой определенные виды объектов (называемых «эмиттеров») выделяют названные события, которые вызывают Функция
объекты («слушатели»), которые будут называться
Этот класс может в некоторой степени описать как помощник в реализации PUB/Sub Model, так как она помогает Эмиттеры событий (издатели) публиковать События (сообщения) и слушатели (подписчики) действовать на эти события – простым способом.
Создание Eventemitters.
Это сказано, давайте пойдем вперед и создадим Eventemitter
Отказ Это можно сделать либо через создание экземпляра самого класса, либо путем внедрения его через пользовательский класс, а затем создание экземпляра этого класса.
Создание объекта Eventemitter
Давайте начнем с простого объекта, излучающего события. Мы создадим Eventemitter
Что выделяет событие, которое содержит информацию о времени безотказной работы приложения, каждую секунду.
Во-первых, импортировать Eventemitter
класс от События
Модули:
const { EventEmitter } = require('events');
Тогда давайте создадим Eventemitter
:
const timerEventEmitter = new EventEmitter();
Чтобы опубликовать событие с этого объекта так же просто, как:
timerEventEmitter.emit("update");
Мы указали имя события и опубликовали его как событие. Ничего не происходит, поскольку нет слушателя, чтобы реагировать на это событие, хотя. Давайте сделаем это событие повторите каждую секунду.
Используя SetInterval ()
Способ, таймер создан, который опубликует Обновить
событие каждую секунду:
let currentTime = 0; // This will trigger the update event each passing second setInterval(() => { currentTime++; timerEventEmitter.emit('update', currentTime); }, 1000);
Eventemitter
Экземпляр принимает имя события и произвольный набор аргументов. В этом случае мы прошли EventName
как Обновить
и текущее время
как время от начала приложения.
Мы запускаем излучатель через Эмит ()
Метод, который толкает событие с информацией, которую мы предоставили.
С нашим событием-эмитром готов, давайте подписаться на событие-слушатель к нему:
timerEventEmitter.on('update', (time) => { console.log('Message Received from publisher'); console.log(`${time} seconds passed since the program started`); });
Используя на ()
Способ, проходящее имя события, чтобы указать, какой из них мы хотели бы прикрепить слушателя, позволяет нам создавать слушателей. На Обновить
Событие, метод запускается, который регистрирует время. Вы можете добавить тот же слушатель снова и снова, и каждый из них будет подписаться на мероприятие.
Второй аргумент на ()
Функция является обратным вызовом, который может принять любое количество дополнительных данных, которые были выпущены событием. Каждый слушатель может выбрать, какие данные они хотят, как только заказ сохраняется.
Запуск этого скрипта должен давать:
Message Received from publisher 1 seconds passed since the program started Message Received from publisher 2 seconds passed since the program started Message Received from publisher 3 seconds passed since the program started ...
Напротив, мы можем использовать один раз ()
Способ подписаться – если вам нужно выполнить что-то только в первый раз, когда событие триггеры:
timerEventEmitter.once('update', (time) => { console.log('Message Received from publisher'); console.log(`${time} seconds passed since the program started`); });
Запуск этого кода даст:
Message Received from publisher 1 seconds passed since the program started
Eventemitter с несколькими слушателями
Теперь давайте сделаем другой вид событий с тремя слушателями. Этот будет обратный отсчет. Один слушатель будет обновлять пользователь каждую секунду, один слушатель уведомляет пользователя, когда обратный отсчет приближается к своему концу, и последний слушатель будет вызвать после окончания обратного отсчета:
Обновить
– Это событие будет вызвать на каждом второмконец
– Это событие срабатывает в конце обратного отсчетаконец - скоро
– Это событие будет вызвать за 2 секунды до завершения обратного отсчета
Давайте создадим функцию, которая создает этот эмиттер событий и возвращает его:
const countDown = (countdownTime) => { const eventEmitter = new EventEmitter(); let currentTime = 0; // This will trigger the update event each passing second const timer = setInterval(() => { currentTime++; eventEmitter.emit('update', currentTime); // Check if countdown has reached to the end if (currentTime === countdownTime) { clearInterval(timer); eventEmitter.emit('end'); } // Check if countdown will end in 2 seconds if (currentTime === countdownTime - 2) { eventEmitter.emit('end-soon'); } }, 1000); return eventEmitter; };
В этой функции мы начали мероприятие на основе интервала, которое излучает Обновить
событие в интервале секунды.
На первом Если
Условие, мы проверяем, достиг отсчета до конца и остановите мероприятие на основе интервала. Если так, мы стреляем конец
мероприятие.
Во втором состоянии мы проверяем, находится ли обратный отсчет в 2 секундах от окончания и публиковать конец - скоро
событие, если так.
Теперь давайте добавим несколько подписчиков на это событие Emitter:
const myCountDown = countDown(5); myCountDown.on('update', (t) => { console.log(`${t} seconds since the timer started`); }); myCountDown.on('end', () => { console.log('Countdown is completed'); }); myCountDown.on('end-soon', () => { console.log('Count down will end in 2 seconds'); });
Этот код должен дать:
1 seconds has been passed since the timer started 2 seconds has been passed since the timer started 3 seconds has been passed since the timer started Count down will end in 2 seconds 4 seconds has been passed since the timer started 5 seconds has been passed since the timer started Countdown is completed
Расширение Eventemitter.
В этом разделе давайте сделаем излучатель события с той же функциональностью, проходяя Eventemitter
класс. Сначала создайте Обратный отсчет
Класс, который будет обрабатывать события:
const { EventEmitter } = require('events'); class CountDown extends EventEmitter { constructor(countdownTime) { super(); this.countdownTime = countdownTime; this.currentTime = 0; } startTimer() { const timer = setInterval(() => { this.currentTime++; this.emit('update', this.currentTime); // Check if countdown has reached to the end if (this.currentTime === this.countdownTime) { clearInterval(timer); this.emit('end'); } // Check if countdown will end in 2 seconds if (this.currentTime === this.countdownTime - 2) { this.emit('end-soon'); } }, 1000); } }
Как видите, мы можем использовать Это .emit ()
внутри класса напрямую. Кроме того, StartTimer ()
Функция используется, чтобы позволить нам контролировать, когда начинается обратный отсчет. В противном случае он начнется, как только объект создан.
Давайте создадим новый объект Обратный отсчет
И подписаться на это:
const myCountDown = new CountDown(5); myCountDown.on('update', (t) => { console.log(`${t} seconds has been passed since the timer started`); }); myCountDown.on('end', () => { console.log('Countdown is completed'); }); myCountDown.on('end-soon', () => { console.log('Count down will be end in 2 seconds'); }); myCountDown.startTimer();
Запуск это приведет к:
1 seconds has been passed since the timer started 2 seconds has been passed since the timer started 3 seconds has been passed since the timer started Count down will be end in 2 seconds 4 seconds has been passed since the timer started 5 seconds has been passed since the timer started Countdown is completed
псевдоним для на ()
Функция это AddListener ()
Отказ Рассмотрим конец - скоро
Слушатель событий:
myCountDown.on('end-soon', () => { console.log('Count down will be end in 2 seconds'); });
Мы могли бы сделать то же самое с AddListener ()
как это:
myCountDown.addListener('end-soon', () => { console.log('Count down will be end in 2 seconds'); });
Они оба работают. Они почти как синонимы. Тем не менее, большинство кодеров предпочитают использовать на ()
Отказ
Важные функции Eventemitter
Давайте посмотрим на некоторые из важных функций, которые мы можем использовать на Eventemitter
с.
EventNames ()
Эта функция вернет все активные имена слушателей в качестве массива:
const myCountDown = new CountDown(5); myCountDown.on('update', (t) => { console.log(`${t} seconds has been passed since the timer started`); }); myCountDown.on('end', () => { console.log('Countdown is completed'); }); myCountDown.on('end-soon', () => { console.log('Count down will be end in 2 seconds'); }); console.log(myCountDown.eventNames());
Запуск этого кода приведет к:
[ 'update', 'end', 'end-soon' ]
Если бы мы должны были подписаться на другое событие, такое как mycount.on («Некоторые события», ...)
Новое событие также будет добавлено в массив.
Имейте в виду, что этот метод не возвращает опубликованные события. Это возвращает список событий, которые подписаны на него.
Removelistener ()
Как предполагает имя, эта функция удаляет подписанный обработчик от Eventemitter
:
const { EventEmitter } = require('events'); const emitter = new EventEmitter(); const f1 = () => { console.log('f1 Triggered'); } const f2 = () => { console.log('f2 Triggered'); } emitter.on('some-event', f1); emitter.on('some-event', f2); emitter.emit('some-event'); emitter.removeListener('some-event', f1); emitter.emit('some-event');
После первого события триггеры, поскольку оба F1
и F2
активны – обе функции будут выполнены. После этого мы удалили F1
от Eventemitter
Отказ Когда мы снова излучаем событие, только F2
будет выполняться:
f1 Triggered f2 Triggered f2 Triggered
псевдоним для Removelistener ()
это ВЫКЛ ()
Отказ Например, мы могли бы написать:
emitter.removeListener('some-event', f1);
В виде:
emitter.off('some-event', f1);
Они оба имеют одинаковый эффект.
RemoveealLlesteners ()
Опять же, как следует из названия – эта функция удалит все слушатели из всех событий Eventemitter
:
const { EventEmitter } = require('events'); const emitter = new EventEmitter(); const f1 = () => { console.log('f1 Triggered'); } const f2 = () => { console.log('f2 Triggered'); } emitter.on('some-event', f1); emitter.on('some-event', f2); emitter.emit('some-event'); emitter.removeAllListeners(); emitter.emit('some-event');
Первый Эмит ()
будет огонь и F1
и F2
Так как они активны в то время. После удаления их Эмит ()
Функция выделяет событие, но никаких слушателей не ответит на него:
f1 Triggered f2 Triggered
Обработка ошибок
Если вы хотите излучить ошибку с помощью вашего Eventemitter
это должно быть сделано с Ошибка
. название события. Это стандарт для всех Eventemitter
Объекты в Node.js. Это событие Должен также сопровождаться Ошибка
. объект. Например, событие ошибки можно излучать так:
myEventEmitter.emit('error', new Error('Something bad happened'));
Любые слушатели для Ошибка
. Событие должно иметь обратный вызов с одним аргументом для захвата Ошибка
. Объект и изящно справиться с этим. Если Eventemitter
излучает Ошибка
. Мероприятие, но нет слушателей подписаны на Ошибка
. События, программа Node.js бросит бы Ошибка
. это было выделено.
Это в конечном итоге будет остановить процесс Node.js от работы и выхода из вашей программы при отображении Stacktrace для ошибки в консоли.
Давайте предположим, в нашем Обратный отсчет
класс, Время отсчета
Параметр не может начать быть менее 2, потому что мы не сможем вызвать событие конец - скоро
иначе.
В таком случае давайте выделяем Ошибка
. мероприятие:
class CountDown extends EventEmitter { constructor(countdownTime) { super(); if (countdownTimer < 2) { this.emit('error', new Error('Value of the countdownTimer cannot be less than 2')); } this.countdownTime = countdownTime; this.currentTime = 0; } // ........... }
Обработка этой ошибки обрабатывается так же, как и другие события:
myCountDown.on('error', (err) => { console.error('There was an error:', err); });
Это считается хорошей практикой, чтобы всегда иметь слушателя для Ошибка
. События.
Родные модули с использованием Eventemitter
Многие родные модули в Node.js расширяют Eventemitter
класс и, таким образом, самими событиями излучатели.
Отличный пример – класс потока. Официальная документация государства:
Потоки могут быть читабельными, записи, или оба. Все потоки – это экземпляры Eventemitter
Отказ
Давайте посмотрим на какую-то классическую Поток
Применение:
const fs = require('fs'); const writer = fs.createWriteStream('example.txt'); for (let i = 0; i < 100; i++) { writer.write(`hello, #${i}!\n`); } writer.on('finish', () => { console.log('All writes are now complete.'); }); writer.end('This is the end\n');
Однако между операцией письма и Writer.end ()
Позвоните, мы добавили слушатель. Поток
s emit a закончил
событие по завершении. Другие события, такие как Ошибка
. , труба
и unpipe
испускаются при возникновении ошибки или поток чтения трубопровод или отсоединен из потока записи.
Другим заметным классом является Child_Process
класс и его Spawn ()
Метод:
const { spawn } = require('child_process'); const ls = spawn('ls', ['-lh', '/usr']); ls.stdout.on('data', (data) => { console.log(`stdout: ${data}`); }); ls.stderr.on('data', (data) => { console.error(`stderr: ${data}`); }); ls.on('close', (code) => { console.log(`child process exited with code ${code}`); });
Когда Child_Process
пишет в стандартную выходную трубу, данные
событие stdout
(который также расширяет событий). Когда выходной поток сталкивается с ошибкой,
данные Событие отправляется из
Стдерр трубка.
Наконец, после выходов процесса Закрыть
событие уволено.
Заключение
Управляемая событием архитектура позволяет нам создавать системы, которые являются отделен Но Высоко сплоченный Отказ События представляют результат определенного действия, а 1..n
Слушатели могут быть определены для прослушивания и реагирования на них.
В этой статье мы погружались в Eventemitter
класс и его функциональность. Мы создали его и использовали его напрямую, а также расширили его поведение в пользовательский объект.
Наконец, мы охватывали некоторые заметные функции класса.
Как всегда, исходный код доступен на Github Отказ