Skip to content

vs-kurkin/EventEmitter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EventEmitter

Расширенная, кросс-платформенная, обратносовместимая реализация модуля EventEmitter из стандартной библиотеки NodeJS. Дополнительное API призвано повысить удобство разработки и читаемость кода. Для этого были внедрены следующие механизмы:

##Отличия от оригинала:

Стандартные события:

  • EventEmitter.MAX_LISTENERS = 10
    Максимальное количество обработчиков события по-умолчанию.

  • EventEmitter.EVENT_NEW_LISTENER = 'newListener'
    Имя события, которое срабатывает при добавлении нового обработчика.

  • EventEmitter.EVENT_REMOVE_LISTENER = 'removeListener'
    Имя события, которое срабатывает при удалении обработчика.

В обработчик события EventEmitter.EVENT_NEW_LISTENER передается три аргумента:

  • {String|Number} type
    Тип события, на которое был добавлен обработчик.

  • {Function|EventEmitter} callback
    Функция или объект-обработчик события.

  • {*} context
    Контекст, в котором будет вызвана функция-обработчик.

Расширенное API подписки на события

Методы подписки на события имеют расширенный интерфейс, а так же новый метод EventEmitter#off:

  • {EventEmitter} EventEmitter#addListener(type, listener[, context])
  • {EventEmitter} EventEmitter#on(type, listener[, context])
  • {EventEmitter} EventEmitter#once(type, listener[, context])
  • {EventEmitter} EventEmitter#removeListener(type, listener)
  • {EventEmitter} EventEmitter#off(type, listener)

Здесь:

  • {String|Number} type
    Тип события.

  • {Function|EventEmitter} listener
    Обработчик события. В отличии от оригинального EventEmitter, обработчиком события может быть другой экземпляр EventEmitter. В этом случае, вместо вызова функции, произойдет вызов одноименного события на объекте-слушателе с передачей всех аргументов оригинального события (см. делегирование событий). Что бы отвязать объект-слушатель, его нужно передать в соответствующий метод удаления обработчика.

  • {Object|null} [context=this]
    Необязательный аргумент, задает контекст обработчика события.

Данные события

Данными события являются все параметры (кроме первого, типа события), переданные в метод EventEmitter#emit. Любой обработчик события может динамически менять набор этих данных.

  • {EventEmitter} EventEmitter#setEventData([...*] args)
    Устанавливает новые данные события. Все переданные аргументы будут доступны в последующих обработчиках текущего события. Если ни одного аргумента не было передано, данные события будут удалены.

  • {Array|null} EventEmitter#getEventData()
    Возвращает текущие данные события в виде массива.

  • {String|Number|null} EventEmitter#getEventType()
    Возвращает тип текущего события.

new EventEmitter()
  .on('event', function (foo) {
    foo === 'bar'; // true
    this.setEventData('baz');
  })
  .on('event', function (foo) {
    foo === 'baz'; // true
    this.setEventData();
  })
  .on('event', function () {
    arguments.length; // 0
    this.getEventType(); // 'event'
  })
  .emit('event', 'bar');

Делегирование событий

Делегирование удобно, если необходимо вызвать событие на одном объекте, когда происходит событие на другом. В оригинальном API пришлось бы написать примерно это:

var emitter = new EventEmitter();
var listener = new EventEmitter();

listener
  .on('otherEvent', function (foo) {
    foo === 'bar'; // true
  });

emitter
  .on('event', function (foo) {
    listener.emit('otherEvent', foo);
  })
  .emit('event', 'bar');

Для подобных ситуаций существует два метода:

  • {EventEmitter} EventEmitter#delegate(emitter, type[, alias=type])
    Делегирует событие type на объект emitter. Необязательным аргументом задается имя события, которое будет вызвано на объекте emitter.

  • {EventEmitter} EventEmitter#unDelegate(emitter, type)
    Снимает делегирование события type на объект emitter.

Вышепреведенный пример теперь можно записать так:

var emitter = new EventEmitter();
var listener = new EventEmitter();

listener
  .on('someEvent', function (foo) {
    foo === 'bar'; // true
  });

emitter
  .delegate(listener, 'event', 'someEvent')
  .emit('event', 'bar');

Следующие строки:

emitter.delegate(listener, 'event');
emitter.delegate(listener, 'event', 'event');

эквивалентны:

emitter.on('event', listener);

, a эта строка:

emitter.unDelegate(listener, 'event');

эквивалентна:

emitter.off('event', listener);

Остановка выполнения обработчиков событий

Стандартное API предполагает безоговорочное выполнение всех обработчиков событий. Возможность остановки выполнения дает дополнительную гибкость в написании логики обработчиков событий.

  • {Boolean} EventEmitter#stopEmit([type])
    Останавливает выполнение обработчиков события текущего объекта. В этом методе так же доступна фильтрация по типу события.

Метод возвращает true, если выполнение обработчиков было остановлено, либо false в противном случае.

Несколько примеров:

new EventEmitter()
  .on('event', function () {
    // Эта строка остановит любое событие,
    // не зависимо от типа или объекта, вызвавшего данное событие.
    this.stopEmit(); // true
  })
  .on('event', function () {
    // Этот обработчик никогда не будет вызван.
  })
  .emit('event');

function listener () {
  this.stopEmit('error'); // true, будет остановлено только событие error
  new EventEmitter().stopEmit(); // false, другой экземпляр не останавливает выполнение
}

new EventEmitter()
  .on('data', listener)
  .on('error', listener)
  .emit('data');

Домены

Не реализованы.

Тесты

Тесты в NodeJS и во всех браузерах:
npm install; npm test.

Сравнение производительности с нативным EventEmitter-ом:
cd tests/benchmark; npm test

About

Extended, cross-platform, backward compatible implementation of the native EventEmitter from NodeJS

Resources

License

Stars

Watchers

Forks

Packages

No packages published