Extended, cross-platform, backward compatible implementation of the native EventEmitter from NodeJS
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
tests
.gitignore
.jshintrc
EventEmitter.js
LICENSE
README.md
karma.conf.js
package.json

README.md

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