Перейти к содержанию

События и модуль events

Для построения более гибкой и масштабируемой архитектуры приложения можно использовать Node.js события, которые представлены классом EventEmitter встроенного модуля events.

Перейдем сразу к примеру.

app.js

const EventEmitter = require('events');

const emitter = new EventEmitter();

emitter.on('message', (message) =>
  console.log('Message: ', message)
);
emitter.on('error', (error) =>
  console.log('Error: ', error)
);

emitter.emit('message', 'Node js EventEmitter in action.');

Генерация Node.js события осуществляется с помощью метода emit() объекта экземпляра класса EventEmitter, который первым аргументом принимает название события, а всеми необязательными остальными - передаваемые данные.

Обработчик регистрируется с использованием метода on(), которому передается два параметра:

  • имя Node.js события;
  • callback-функция, принимающая в качестве параметров указанные в emit() данные.

Если в процессе генерации события произойдет ошибка, то Node.js самостоятельно инициирует возникновение события error, и если для него не будет найден обработчик, то будет сгенерировано исключение.

Экземпляры EventEmitter

Обычно в приложении создаются несколько экземпляров класса EventEmitter для логического разграничения типов Node.js событий.

app.js

const EventEmitter = require('events');

class EmitterOne extends EventEmitter {}
class EmitterTwo extends EventEmitter {}

const emitterOneInstance = new EmitterOne();
const emitterTwoInstance = new EmitterTwo();

emitterOneInstance.on('message', (message) =>
  console.log('Emitter one message: ', message)
);
emitterOneInstance.on('error', (error) =>
  console.log('Emitter one error: ', error)
);

emitterTwoInstance.on('message', (message) =>
  console.log('Emitter two message: ', message)
);
emitterTwoInstance.on('error', (error) =>
  console.log('Emitter two error: ', error)
);

emitterOneInstance.emit(
  'message',
  'Node js EventEmitter in action.'
);

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

EventEmitter API

Для однократного выполнения регистрируемого обработчика вместо метода on() используйте once(), который перед вызовом callback-функции удаляет его из памяти.

app.js

const EventEmitter = require('events');

const emitter = new EventEmitter();

emitter.once('message', (message) =>
  console.log('Message: ', message)
); //выполнится один раз

emitter.emit('message', 'First');
emitter.emit('message', 'Second');

По умолчанию для каждого отдельного события можно максимально зарегистрировать 10 функций обработчиков. Чтобы снять это ограничение для всех событий всех созданных экземпляров, измените значение свойства EventEmitter.defaultMaxListeners.

app.js

const EventEmitter = require('events');

EventEmitter.defaultMaxListeners = 1;

const emitter = new EventEmitter();

emitter.on('message', (message) =>
  console.log('Listener 1: ', message)
);
emitter.on('message', (message) =>
  console.log('Listener 2: ', message)
);

emitter.emit('message', 'Message');

Чтобы изменить ограничение для отдельного экземпляра, используйте применительно к нему метод setMaxListeners().

const emitter = new EventEmitter();

emitter.setMaxListeners(1);

В случае превышения максимального количества обработчиков Node.js события будет выдано предупреждение.

Чтобы узнать, сколько обрабатывающих функций уже зарегистрировано на конкретное событие, используйте метод EventEmitter.listenerCount(), которому передаются два параметра:

  • экземпляр EventEmitter, относительно которого было зарегистрировано событие;
  • имя события.

app.js

const EventEmitter = require('events');

const emitter = new EventEmitter();

emitter.on('message', (message) =>
  console.log('Listener 1: ', message)
);
emitter.on('message', (message) =>
  console.log('Listener 2: ', message)
);

console.log(EventEmitter.listenerCount(emitter, 'message')); //2

Получить все зарегистрированные события позволяет метод eventNames().

emitter.on('message', (message) =>
  console.log('Message: ', message)
);
emitter.on('error', (error) =>
  console.log('Error: ', error)
);

console.log(emitter.eventNames()); //['message', 'error']

Для удаления определенного обработчика у отдельного события используйте метод removeListener(), принимающий в качестве параметров имя Node.js события и сам обработчик.

const messageListener = (message) =>
  console.log('Message: ', message);

emitter.on('message', messageListener);

emitter.emit('message', 'First');

emitter.removeListener('message', messageListener);

emitter.emit('message', 'Second'); //на этом этапе обработичка уже нет

Для удаления всех обработчиков события или сразу нескольких событий, используйте метод removeAllListeners(), который принимает массив событий, обработчики которых необходимо удалить.

const messageListener1 = (message) =>
  console.log('Message listener 1: ', message);
const messageListener2 = (message) =>
  console.log('Message listener 2: ', message);
const errorListener = (error) =>
  console.log('Error: ', error);

emitter.on('message', messageListener1);
emitter.on('message', messageListener2);
emitter.on('error', errorListener);

emitter.emit('message', 'First');

emitter.removeAllListeners(['message']);

emitter.emit('message', 'Second'); //на этом этапе обработичков уже нет