Рубрики
Без рубрики

Как кодировать свой собственный эмиттер событий в Node.js: пошаговое руководство

Rajesh Pillai, как кодировать свой собственный эмиттер событий в Node.js: пошаговое направляющее внутренние внутренние узлы, кодирующие небольшие пакеты / модулимастеринг узла. Js Internalsif Вы новичок в Node.js Есть много учебных пособий здесь на среднем и в другом месте. Вы можете проверить мою статью все о

Автор оригинала: FreeCodeCamp Community Member.

Rajesh Pillai

Понимать внутренние ноты узла путем кодирования небольших пакетов/модулей

Если вы новичок в Node.js Есть много учебников здесь, на среднем и в другом месте. Вы можете проверить мою статью Все о базовом узле. JS , Например.

Но без дальнейшего ADO давайте доберемся до обсуждения темы: «Эмиттеры событий». Эмиттеры событий играют очень важную роль в экосистеме Node.js.

Eventemitter – это модуль, который облегчает связь/взаимодействие между объектами в узле. Eventemitter находится в ядре узла асинхронной архитектуры, управляемой событием. Многие встроенные модули узла наследуют от Eventemitter, включая заметные рамки, такие как Express.js.

Концепция довольно проста: объекты эмиттера выделяют названные события, которые вызывают ранее зарегистрированные слушатели, которые будут называться. Итак, объект эмиттера в основном имеет две основные особенности:

  • Излучающие имени события.
  • Регистрация и незарегистрированные функции слушателя.

Это вроде как паб/субзаконный узор из паба или наблюдателя (хотя не совсем).

Что мы будем строить в этом руководстве

  • Класс Eventemitter
  • ВКЛ/addeventListener Метод
  • OFF/RemoveeventListener Метод
  • однажды метод
  • метод Emit.
  • Метод RawListeners
  • Способ прослушивания

Вышеуказанные основные функции достаточны для реализации полной системы с использованием моделированной модели.

Прежде чем мы попадем в кодировку, давайте посмотрим, как мы будем использовать класс Eventemitter. Обратите внимание, что наш код будет имитировать точные API модуля событий Node.js.

Фактически, если вы замените наш Eventemitter встроенные «события событий Node.js», вы получите тот же результат.

Пример 1 – Создание экземпляра Emitter событий и зарегистрируйте пару обратных вызовов

const myEmitter = new EventEmitter();

function c1() {
   console.log('an event occurred!');
}

function c2() {
   console.log('yet another event occurred!');
}

myEmitter.on('eventOne', c1); // Register for eventOne
myEmitter.on('eventOne', c2); // Register for eventOne

Когда испускается событие «EventOne», как приведенные выше обратные вызовы должны быть вызваны.

myEmitter.emit('eventOne');

Выход в консоли будет следующим образом:

an event occurred!
yet another event occurred!

Пример 2- Регистрация для события, которое будет выпущено только один раз, используя один раз.

myEmitter.once('eventOnce', () => console.log('eventOnce once fired'));  

Выпуская событие «EventOnce»:

myEmitter.emit('eventOne');

Следующий вывод должен появиться в консоли:

eventOnce once fired

Излучающие события, зарегистрированные в очередной раз, не будут никакого влияния.

myEmitter.emit('eventOne');

Поскольку мероприятие было выпущено только один раз, приведенное выше заявление не окажет влияния.

Пример 3- Регистрация события с параметрами обратного вызова

myEmitter.on('status', (code, msg)=> console.log(`Got ${code} and ${msg}`));

Выпуская событие с параметрами:

myEmitter.emit('status', 200, 'ok');

Выход в консоли будет как ниже:

Got 200 and ok

Примечание. Вы можете излучать события несколько раз (кроме тех, которые зарегистрированы с последующим методом).

Пример 4- Незарегистрированные события

myEmitter.off('eventOne', c1);

Теперь, если вы излучаете событие следующим образом, ничего не произойдет, и это будет NOOP:

myEmitter.emit('eventOne');  // noop

Пример 5- Получение подсчета слушателя

console.log(myEmitter.listenerCount('eventOne'));

ЗАМЕТКА: Если событие было незарегистрировано, используя метод OFF или Removelistener, то счет будет 0.

Пример 6- Получение необработанных слушателей

console.log(myEmitter.rawListeners('eventOne'));

Пример 7- Async пример демонстрации

// Example 2->Adapted and thanks to Sameer Buna
class WithTime extends EventEmitter {
  execute(asyncFunc, ...args) {
    this.emit('begin');
    console.time('execute');
    this.on('data', (data)=> console.log('got data ', data));
    asyncFunc(...args, (err, data) => {
      if (err) {
        return this.emit('error', err);
      }
      this.emit('data', data);
      console.timeEnd('execute');
      this.emit('end');
    });
  }
}

Использование излучателя события со временем:

const withTime = new WithTime();

withTime.on('begin', () => console.log('About to execute'));
withTime.on('end', () => console.log('Done with execute'));

const readFile = (url, cb) => {
  fetch(url)
    .then((resp) => resp.json()) // Transform the data into json
    .then(function(data) {
      cb(null, data);
    });
}

withTime.execute(readFile, 'https://jsonplaceholder.typicode.com/posts/1');

Проверьте выходные данные в консоли. Список постов будет отображаться вместе с другими журналами.

Узор наблюдателя для нашего эмиттера мероприятия

Визуальная диаграмма 1 (методы в нашем событии)

Так как мы теперь понимаем API использования, давайте доберемся к кодированию модуля.

Полный код котельной для класса Eventemitter

Мы будем заполнять детали постепенно на следующей паре разделов.

class EventEmitter {
  listeners = {};  // key-value pair
  
  addListener(eventName, fn) {}
  on(eventName, fn) {}
  
  removeListener(eventName, fn) {}
  off(eventName, fn) {}
  
  once(eventName, fn) {}
  
  emit(eventName, ...args) { }
  
  listenerCount(eventName) {}
  
  rawListeners(eventName) {}
}

Мы начинаем с создания шаблона для класса Eventemitter вместе с хешем для хранения слушателей. Слушатели будут храниться в виде пары ключа. Значение может быть массивом (поскольку для того же события, которое мы позволяем зарегистрировано нескольким слушателям).

1. Метод addListener ()

Давайте теперь будем реализовать метод AddListener. Он принимает имя события и функцию обратного вызова для выполнения.

  addListener(event, fn) {
    this.listeners[event] = this.listeners[event] || [];
    this.listeners[event].push(fn);
    return this;
  }

Немного объяснения:

Событие AddListener проверяет, будет ли событие уже зарегистрировано. Если да, возвращает массив, в противном случае пустой массив.

this.listeners[event] // will return array of events or undefined (first time registration)

Например…

Давайте понять это с примером использования. Давайте создадим новый Eventemitter и зарегистрируйте «тестовое событие». Это первый раз, когда «Test-Event» зарегистрирован.

const eventEmitter = new EventEmitter();
eventEmitter.addListener('test-event', 
 ()=> { console.log ("test one") } 
);

Внутри дополнителя () Метод:

this.listeners[event] =>  this.listeners['test-event'] 
                  => undefined || []
                  => []

Результатом будет:

this.listeners['test-event'] = [];  // empty array

И тогда «FN» будет нажата на этот массив, как показано ниже:

this.listeners['test-event'].push(fn);

Я надеюсь, что это делает метод «AddListener», чтобы расшифровать и понять.

Примечание: несколько обратных вызовов могут быть зарегистрированы против этого же события.

2. То на методе

Это просто псевдоним для метода «AddListener». Мы будем использовать метод «ON» больше, чем метод «AddListener» для удобства.

on(event, fn) {
  return this.addListener(event, fn);
}

3. Метод Removelistener (события, FN)

Метод Removelistener принимает EventName и обратный вызов как параметры. Удаляет указанный слушатель из массива событий.

ЗАМЕТКА: Если у мероприятия есть несколько слушателей, то другие слушатели не будут затронуты.

Во-первых, давайте посмотрим на полный код для Removelistener.

removeListener (event, fn) {
    let lis = this.listeners[event];
    if (!lis) return this;
    for(let i = lis.length; i > 0; i--) {
      if (lis[i] === fn) {
        lis.splice(i,1);
        break;
      }
    }
    return this;
}

Вот метод Removelistener объяснил пошаговый шаг:

  • Возьмите на массив слушателей по «мероприятию»
  • Если никто не нашел возвращения «это» для цепочки.
  • Если найдено, петля через все слушатели. Если текущий слушатель совпадает с параметром «Fn», используйте метод SPLICE, чтобы удалить его. Перерыв из петли.
  • Вернуть «Это», чтобы продолжить цепочку.

4. Метод OFF (события, FN)

Это просто псевдоним методом «Removelistener». Мы будем использовать метод «ON» больше, чем метод «AddListener» для удобства.

  off(event, fn) {
    return this.removeListener(event, fn);
  }

5. Метод один раз (EventName, Fn)

Добавляет одноразовый Слушатель Функция для мероприятия с именем EventName Отказ В следующий раз EventName Срабатывает, этот слушатель удален, а затем вызывается.

Используйте для настройки/инициативы событий.

Давайте покой на код.

once(eventName, fn) {
    this.listeners[event] = this.listeners[eventName] || [];
    const onceWrapper = () => {
      fn();
      this.off(eventName, onceWrapper);
    }
    this.listeners[eventName].push(onceWrapper);
    return this;
}

Вот …| Однажды Метод объяснил пошаговый шаг:

  • Получите объект массива событий. Пустой массив, если первый раз.
  • Создайте функцию обертки под названием DownWrapber, которая призывает Fn, когда событие испускается, а также удаляет слушатель.
  • Добавьте обернутую функцию в массив.
  • Вернуть «Это» для цепочки.

6. Метод Emit (Eventname, aargs)

Синхронно вызывает каждый из слушателей, зарегистрированных для мероприятия, названного EventName В приказе они были зарегистрированы, передавая прилагаемые аргументы каждому.

Возвращает правда Если у этого события слушатели, ложь иначе.

emit(eventName, ...args) {
    let fns = this.listeners[eventName];
    if (!fns) return false;
    fns.forEach((f) => {
      f(...args);
    });
    return true;
}

Вот …| Эмит Метод объяснил пошаговый шаг:

  • Получите функции для указанного параметра EventName
  • Если нет слушателей, верните ложь
  • Для всех слушателей функции вызовите функцию с аргументами
  • Вернуть правда когда сделано

7. Метод прослушивания (Eventname)

Возвращает количество слушателей, слушающих событие с именем EventName Отказ

Вот исходный код:

listenerCount(eventName) {
    let fns = this.listeners[eventName] || [];
    return fns.length;
}

Вот метод прослушивания объяснил пошаговый шаг:

  • Получите рассмотрение функций/слушателей или пустой массив, если нет.
  • Вернуть длину.

8. Метод RawListeners (Eventname)

Возвращает копию массива слушателей для мероприятия с именем EventName , в том числе любые обертки (такие как те, которые созданы .once () ). Когда-то обертки в этой реализации не будут доступны, если событие выделяется один раз.

rawListeners(event) {
    return this.listeners[event];
}

Полный исходный код для справки:

class EventEmitter {
  listeners = {}
  
  addListener(eventName, fn) {
    this.listeners[eventName] = this.listeners[eventName] || [];
    this.listeners[eventName].push(fn);
    return this;
  }

  on(eventName, fn) {
    return this.addListener(eventName, fn);
  }

  once(eventName, fn) {
    this.listeners[eventName] = this.listeners[eventName] || [];
    const onceWrapper = () => {
      fn();
      this.off(eventName, onceWrapper);
    }
    this.listeners[eventName].push(onceWrapper);
    return this;
  }

  off(eventName, fn) {
    return this.removeListener(eventName, fn);
  }

  removeListener (eventName, fn) {
    let lis = this.listeners[eventName];
    if (!lis) return this;
    for(let i = lis.length; i > 0; i--) {
      if (lis[i] === fn) {
        lis.splice(i,1);
        break;
      }
    }
    return this;
  }

  emit(eventName, ...args) {
    let fns = this.listeners[eventName];
    if (!fns) return false;
    fns.forEach((f) => {
      f(...args);
    });
    return true;
  }

  listenerCount(eventName) {
    let fns = this.listeners[eventName] || [];
    return fns.length;
  }

  rawListeners(eventName) {
    return this.listeners[eventName];
  }
}

Полный код доступен здесь:

Поскольку упражнение не стесняйтесь реализовывать API других событий из документации https://nodejs.org/api/events.html Отказ

Если вам понравилась эта статья и хочу увидеть больше похожих статей, не стесняйтесь дать пару хлопья:)

Примечание : Код оптимизирован для читаемости, а не для производительности. Может быть, как упражнение, вы можете оптимизировать код и поделиться его в разделе комментариев. Не полностью тестировали для кромки, а некоторые валидации могут быть выключены, так как это была быстрая запись.

Эта статья является частью предстоящего узла видео-курса. JS Master Class – построить собственные собственные Frameworks, как Framework MVC с нуля ».

Название курса еще не доработана.

Оригинал: “https://www.freecodecamp.org/news/how-to-code-your-own-event-emitter-in-node-js-a-step-by-step-guide-e13b7e7908e1/”