Spec-Zone.ru › Node.js 4 LTS

События

Стабильность: 2 — Стабильно

Большая часть ядра Node.js API построена вокруг идиоматичной асинхронной архитектуры обработки событий, в которой определённые типы объектов (называемые «эмиттерами») периодически излучают именованные события, вызывающие функции («слушатели»).

Например: объект net.Server излучает событие каждый раз, когда к нему подключается узел; объект fs.ReadStream излучает событие при открытии файла; поток stream излучает событие всякий раз, когда доступны данные для чтения.

Все объекты, излучающие события, являются экземплярами класса EventEmitter. Эти объекты предоставляют функцию eventEmitter.on(), которая позволяет прикрепить одну или несколько функций к именованным событиям, излучаемым объектом. Обычно имена событий — это строковые значения в верхнем регистре, но можно использовать любые допустимые ключи свойств JavaScript.

Когда объект EventEmitter излучает событие, все функции, прикреплённые к этому конкретному событию, вызываются синхронно. Любые значения, возвращаемые вызываемыми слушателями, игнорируются и будут отброшены.

Следующий пример демонстрирует простой экземпляр EventEmitter с одним слушателем. Метод eventEmitter.on() используется для регистрации слушателей, а метод eventEmitter.emit() используется для запуска события.

const EventEmitter = require('events');
const util = require('util');

function MyEmitter() {
  EventEmitter.call(this);
}
util.inherits(MyEmitter, EventEmitter);

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});
myEmitter.emit('event');

Любой объект может стать EventEmitter через наследование. В приведённом выше примере используется традиционный прототипный стиль наследования Node.js, использующий метод util.inherits(). Однако также можно использовать классы ES6:

const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});
myEmitter.emit('event');

Передача аргументов и this слушателям

Метод eventEmitter.emit() позволяет передавать произвольный набор аргументов функциям-слушателям. Важно помнить, что при вызове обычной функции-слушателя объектом EventEmitter, стандартное ключевое слово this намеренно устанавливается для ссылки на экземпляр EventEmitter, к которому прикреплён слушатель.

const myEmitter = new MyEmitter();
myEmitter.on('event', function(a, b) {
  console.log(a, b, this);
    // Prints:
    //   a b MyEmitter {
    //     domain: null,
    //     _events: { event: [Function] },
    //     _eventsCount: 1,
    //     _maxListeners: undefined }
});
myEmitter.emit('event', 'a', 'b');

Использование функций ES6 Arrow в качестве слушателей возможно, однако в этом случае ключевое слово this больше не будет ссылаться на экземпляр EventEmitter:

const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  console.log(a, b, this);
    // Prints: a b {}
});
myEmitter.emit('event', 'a', 'b');

Асинхронный и синхронный режимы

Объект EventListener вызывает всех слушателей синхронно в порядке их регистрации. Это важно для обеспечения правильной последовательности событий и предотвращения гонок или логических ошибок. При необходимости функции-слушатели могут переключиться на асинхронный режим работы, используя методы setImmediate() или process.nextTick():

const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  setImmediate(() => {
    console.log('this happens asynchronously');
  });
});
myEmitter.emit('event', 'a', 'b');

Обработка событий только один раз

При регистрации слушателя с помощью метода eventEmitter.on() этот слушатель будет вызываться каждый раз при излучении именованного события.

const myEmitter = new MyEmitter();
var m = 0;
myEmitter.on('event', () => {
  console.log(++m);
});
myEmitter.emit('event');
  // Prints: 1
myEmitter.emit('event');
  // Prints: 2

Используя метод eventEmitter.once(), можно зарегистрировать слушателя, который будет дерегистрирован до своего вызова.

const myEmitter = new MyEmitter();
var m = 0;
myEmitter.once('event', () => {
  console.log(++m);
});
myEmitter.emit('event');
  // Prints: 1
myEmitter.emit('event');
  // Ignored

События ошибок

Когда в экземпляре EventEmitter возникает ошибка, типичным действием является излучение события 'error'. Они обрабатываются как особый случай в Node.js.

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

const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));
  // Throws and crashes Node.js

Чтобы предотвратить аварийное завершение процесса Node.js, разработчики могут либо зарегистрировать слушателя для события process.on('uncaughtException') , либо использовать модуль domain (Обратите внимание, что модуль domain устарел).

const myEmitter = new MyEmitter();

process.on('uncaughtException', (err) => {
  console.log('whoops! there was an error');
});

myEmitter.emit('error', new Error('whoops!'));
  // Prints: whoops! there was an error

В качестве рекомендации разработчики должны всегда регистрировать слушателей для события 'error':

const myEmitter = new MyEmitter();
myEmitter.on('error', (err) => {
  console.log('whoops! there was an error');
});
myEmitter.emit('error', new Error('whoops!'));
  // Prints: whoops! there was an error

Класс: EventEmitter

Добавлен в: v0.1.26

Класс EventEmitter определён и доступен в модуле events:

const EventEmitter = require('events');

Все EventEmitter излучают событие 'newListener' при добавлении новых слушателей и событие 'removeListener' при удалении слушателя.

Событие: 'newListener'

Добавлен в: v0.1.26
  • eventName <Строка> | <Символ> Имя события, на которое подписываются
  • listener <Функция> Функция-обработчик события

Экземпляр EventEmitter излучит собственное событие 'newListener' до добавления слушателя в его внутренний массив слушателей.

Слушатели, зарегистрированные для события 'newListener' , получат имя события и ссылку на добавляемый слушатель.

Тот факт, что событие срабатывает до добавления слушателя, имеет тонкий, но важный побочный эффект: любые дополнительные слушатели, зарегистрированные для того же события name внутри обратного вызова 'newListener' , будут вставлены перед слушателем, который в процессе добавления.

const myEmitter = new MyEmitter();
// Only do this once so we don't loop forever
myEmitter.once('newListener', (event, listener) => {
  if (event === 'event') {
    // Insert a new listener in front
    myEmitter.on('event', () => {
      console.log('B');
    });
  }
});
myEmitter.on('event', () => {
  console.log('A');
});
myEmitter.emit('event');
  // Prints:
  //   B
  //   A

Событие: 'removeListener'

Добавлен в: v0.9.3
  • eventName <Строка> | <Символ> Имя события
  • listener <Функция> Функция-обработчик события

Событие 'removeListener' излучается после удаления слушателя.

EventEmitter.listenerCount(emitter, eventName)

Добавлен в: v0.9.12 Устарел с: v4.0.0
Стабильность: 0 — Устарел: Используйте emitter.listenerCount() вместо этого.

Метод класса, возвращающий количество слушателей для данного eventName , зарегистрированных на данном emitter.

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {});
myEmitter.on('event', () => {});
console.log(EventEmitter.listenerCount(myEmitter, 'event'));
  // Prints: 2

EventEmitter.defaultMaxListeners

Добавлен в: v0.11.2

По умолчанию максимальное количество слушателей, которое может быть зарегистрировано для любого отдельного события, равно 10. Этот предел можно изменить для отдельных экземпляров EventEmitter с помощью метода emitter.setMaxListeners(n). Чтобы изменить значение по умолчанию для всех экземпляров EventEmitter , можно использовать свойство EventEmitter.defaultMaxListeners.

Будьте осторожны при установке EventEmitter.defaultMaxListeners, так как это изменение повлияет на все экземпляры EventEmitter , включая те, которые были созданы до внесения изменения. Однако вызов emitter.setMaxListeners(n) всё ещё имеет приоритет над EventEmitter.defaultMaxListeners.

Обратите внимание, что это не жёсткий лимит. Экземпляр EventEmitter позволит добавить больше слушателей, но выведет предупреждение в stderr, показывая, что обнаружено превышение предела possible EventEmitter memory leak . Для каждого отдельного EventEmitter, можно временно избежать этого предупреждения с помощью методов emitter.getMaxListeners() и emitter.setMaxListeners():

emitter.setMaxListeners(emitter.getMaxListeners() + 1);
emitter.once('event', () => {
  // do stuff
  emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
});

emitter.addListener(eventName, listener)

Добавлен в: v0.1.26

Псевдоним для emitter.on(eventName, listener).

emitter.emit(eventName[, arg1][, arg2][, ...])

Добавлен в: v0.1.26

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

Возвращает true , если у события были слушатели, false в противном случае.

emitter.getMaxListeners()

Добавлен в: v1.0.0

Возвращает текущее максимальное значение слушателей для EventEmitter , которое установлено с помощью emitter.setMaxListeners(n) или по умолчанию соответствует EventEmitter.defaultMaxListeners.

emitter.listenerCount(eventName)

Добавлен в: v3.2.0
  • eventName <Значение> Имя события, на которое подписываются

Возвращает количество слушателей, подписанных на событие с именем eventName.

emitter.listeners(eventName)

Добавлен в: v0.1.26

Возвращает копию массива слушателей для события с именем eventName.

server.on('connection', (stream) => {
  console.log('someone connected!');
});
console.log(util.inspect(server.listeners('connection')));
  // Prints: [ [Function] ]

emitter.on(eventName, listener)

Добавлен в: v0.1.101

Добавляет функцию listener в конец массива слушателей для события с именем eventName. Проверки, что функция listener уже добавлена, не производится. Несколько вызовов с одинаковой комбинацией eventName и listener приведут к добавлению и вызову listener несколько раз.

server.on('connection', (stream) => {
  console.log('someone connected!');
});

Возвращает ссылку на EventEmitter, чтобы вызовы можно было объединить.

emitter.once(eventName, listener)

Добавлен в: v0.3.0

Добавляет функцию-слушатель listener для события с именем eventName. При следующем срабатывании eventName этот слушатель удаляется и затем вызывается.

server.once('connection', (stream) => {
  console.log('Ah, we have our first user!');
});

Возвращает ссылку на EventEmitter, чтобы вызовы можно было объединить.

emitter.removeAllListeners([eventName])

Добавлен в: v0.1.26

Удаляет всех слушателей или тех, которые указаны по имени eventName.

Обратите внимание, что удаление слушателей, добавленных в другом месте кода, особенно когда экземпляр EventEmitter был создан какой-либо другой компонентой или модулем (например, сокетами или потоками файлов), является плохой практикой.

Возвращает ссылку на EventEmitter, чтобы вызовы можно было объединить.

emitter.removeListener(eventName, listener)

Добавлен в: v0.1.26

Удаляет указанного listener из массива слушателей для события с именем eventName.

var callback = (stream) => {
  console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback);

removeListener удалит, как максимум, один экземпляр слушателя из массива слушателей. Если какой-либо отдельный слушатель был добавлен несколько раз в массив слушателей для указанного eventName, то removeListener необходимо вызвать несколько раз, чтобы удалить каждый экземпляр.

Обратите внимание, что после того, как событие было излучено, все слушатели, прикрепленные к нему в момент излучения, будут вызваны в порядке. Это подразумевает, что любые вызовы removeListener() или removeAllListeners() после излучения и перед завершением работы последнего слушателя не удалят их из emit() в процессе. Последующие события будут работать как ожидается.

const myEmitter = new MyEmitter();

var callbackA = () => {
  console.log('A');
  myEmitter.removeListener('event', callbackB);
};

var callbackB = () => {
  console.log('B');
};

myEmitter.on('event', callbackA);

myEmitter.on('event', callbackB);

// callbackA removes listener callbackB but it will still be called.
// Internal listener array at time of emit [callbackA, callbackB]
myEmitter.emit('event');
  // Prints:
  //   A
  //   B

// callbackB is now removed.
// Internal listener array [callbackA]
myEmitter.emit('event');
  // Prints:
  //   A

Поскольку слушатели управляются с помощью внутреннего массива, вызов этого метода изменит индексы позиции любого слушателя, зарегистрированного после удаляемого слушателя. Это не повлияет на порядок вызова слушателей, но это означает, что любые копии массива слушателей, возвращаемые методом emitter.listeners(), необходимо будет пересоздать.

Возвращает ссылку на EventEmitter, чтобы вызовы можно было объединить.

emitter.setMaxListeners(n)

Добавлен в: v0.3.5

По умолчанию EventEmitters будут выводить предупреждение, если для определенного события будет добавлено более 10 слушателей. Это полезный стандартный параметр, который помогает найти утечки памяти. Очевидно, что не все события должны быть ограничены всего 10 слушателями. Метод emitter.setMaxListeners() позволяет изменить ограничение для этого конкретного экземпляра EventEmitter. Значение можно установить на Infinity (или 0), чтобы указать неограниченное количество слушателей.

Возвращает ссылку на EventEmitter, чтобы вызовы можно было объединить.

© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v4.x/docs/api/events.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API