Spec-Zone.ru › Node.js 14 LTS

События

Устойчивость: 2 - Стабильно

Исходный код: lib/events.js

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

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

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

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

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

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() позволяет передавать произвольное множество аргументов функциям-слушателям. Имейте в виду, что при вызове обычной функции-слушателя стандартный ключевой параметр this преднамеренно используется для ссылки на экземпляр EventEmitter, к которому прикреплен слушатель.

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

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

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

Асинхронность против синхронности

Метод EventEmitter вызывает всех слушателей синхронно в порядке их регистрации. Это гарантирует правильную последовательность событий и помогает избежать гонок и логических ошибок. В подходящих случаях функции-слушатели могут переключаться на асинхронный режим работы, используя методы 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();
let m = 0;
myEmitter.on('event', () => {
  console.log(++m);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Prints: 2

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

const myEmitter = new MyEmitter();
let 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 можно использовать модуль domain. (Обратите внимание, что модуль domain устарел.)

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

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

Возможен мониторинг событий 'error' без потребления сгенерированной ошибки путём установки слушателя с использованием символа errorMonitor.

const myEmitter = new MyEmitter();
myEmitter.on(EventEmitter.errorMonitor, (err) => {
  MyMonitoringTool.log(err);
});
myEmitter.emit('error', new Error('whoops!'));
// Still throws and crashes Node.js

Перехват отклонений обещаний

Устойчивость: 1 - captureRejections экспериментальная.

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

const ee = new EventEmitter();
ee.on('something', async (value) => {
  throw new Error('kaboom');
});

Параметр captureRejections в конструкторе EventEmitter или глобальная настройка изменяют это поведение, устанавливая обработчик .then(undefined, handler) для Promise. Этот обработчик асинхронно перенаправляет исключение в метод Symbol.for('nodejs.rejection'), если он есть, или в обработчик события 'error', если его нет.

const ee1 = new EventEmitter({ captureRejections: true });
ee1.on('something', async (value) => {
  throw new Error('kaboom');
});

ee1.on('error', console.log);

const ee2 = new EventEmitter({ captureRejections: true });
ee2.on('something', async (value) => {
  throw new Error('kaboom');
});

ee2[Symbol.for('nodejs.rejection')] = console.log;

Установка EventEmitter.captureRejections = true изменит значение по умолчанию для всех новых экземпляров EventEmitter.

EventEmitter.captureRejections = true;
const ee1 = new EventEmitter();
ee1.on('something', async (value) => {
  throw new Error('kaboom');
});

ee1.on('error', console.log);

События 'error', генерируемые поведением captureRejections, не имеют обработчика catch, чтобы избежать бесконечных циклов ошибок: рекомендуется не использовать функции async в качестве обработчиков событий 'error'.

Класс: EventEmitter

История
Версия Изменения
v13.4.0, v12.16.0

Добавлен параметр captureRejections.

v0.1.26

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

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

const EventEmitter = require('events');

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

Он поддерживает следующие параметры:

  • captureRejections <boolean> Включает автоматическое перехват отмены обещаний. По умолчанию: false.

Событие: 'newListener'

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

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

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

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

class MyEmitter extends EventEmitter {}

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'

История
Версия Изменения
v6.1.0, v4.7.0

Для слушателей, подключенных с помощью .once(), аргумент listener теперь возвращает исходную функцию обработчика.

v0.9.3

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

  • eventName <string> | <symbol> Имя события
  • listener <Функция> Функция обработчика события

Событие 'removeListener' эмитируется после удаления listener.

EventEmitter.listenerCount(emitter, eventName)

Добавлен в: v0.9.12Устарел с: v3.2.0
Уровень стабильности: 0 - Устарел: Используйте emitter.listenerCount() вместо этого.
  • emitter <EventEmitter> Эмиттер для запроса
  • eventName <string> | <symbol> Имя события

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

const myEmitter = new EventEmitter();
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 . Если это значение не является положительным числом, будет выброшено RangeError.

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

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

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

Флаг командной строки --trace-warnings может быть использован для отображения стека вызовов для таких предупреждений.

Выведенное предупреждение можно просмотреть с помощью process.on('warning') и оно будет иметь дополнительные свойства emitter, type и count, относящиеся к экземпляру эмиттера событий, имени события и количеству подключенных слушателей соответственно. Его свойство name установлено в 'MaxListenersExceededWarning'.

EventEmitter.errorMonitor

Добавлен в: v13.6.0, v12.16.0

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

Установка слушателя с помощью этого символа не меняет поведение после выдачи события 'error' , поэтому процесс всё равно завершится аварийно, если не установлен ни один обычный слушатель 'error'.

EventEmitter.setMaxListeners(n[, ...eventTargets])

Добавлен в: v14.17.0
  • n <число> Неотрицательное число. Максимальное количество слушателей на событие EventTarget.
  • ...eventsTargets <EventTarget[]> | <EventEmitter[]> Ноль или более экземпляров <EventTarget> или <EventEmitter>. Если не указано ничего, n устанавливается в качестве максимального значения по умолчанию для всех вновь созданных объектов <EventTarget> и <EventEmitter>.
const {
  setMaxListeners,
  EventEmitter
} = require('events');

const target = new EventTarget();
const emitter = new EventEmitter();

setMaxListeners(5, target, emitter);

emitter.addListener(eventName, listener)

Добавлен в: v0.1.26
  • eventName <string> | <symbol>
  • listener <Функция>

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

emitter.emit(eventName[, ...args])

Добавлен в: v0.1.26
  • eventName <string> | <symbol>
  • ...args <любой>
  • Возвращает: <boolean>

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

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

const EventEmitter = require('events');
const myEmitter = new EventEmitter();

// First listener
myEmitter.on('event', function firstListener() {
  console.log('Helloooo! first listener');
});
// Second listener
myEmitter.on('event', function secondListener(arg1, arg2) {
  console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
});
// Third listener
myEmitter.on('event', function thirdListener(...args) {
  const parameters = args.join(', ');
  console.log(`event with parameters ${parameters} in third listener`);
});

console.log(myEmitter.listeners('event'));

myEmitter.emit('event', 1, 2, 3, 4, 5);

// Prints:
// [
//   [Function: firstListener],
//   [Function: secondListener],
//   [Function: thirdListener]
// ]
// Helloooo! first listener
// event with parameters 1, 2 in second listener
// event with parameters 1, 2, 3, 4, 5 in third listener

emitter.eventNames()

Добавлен в: v6.0.0
  • Возвращает: <Массив>

Возвращает массив, содержащий список событий, для которых эмиттер зарегистрировал слушателей. Значения в массиве — строки или Symbol.

const EventEmitter = require('events');
const myEE = new EventEmitter();
myEE.on('foo', () => {});
myEE.on('bar', () => {});

const sym = Symbol('symbol');
myEE.on(sym, () => {});

console.log(myEE.eventNames());
// Prints: [ 'foo', 'bar', Symbol(symbol) ]

emitter.getMaxListeners()

Добавлен в: v1.0.0
  • Возвращает: <целое>

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

emitter.listenerCount(eventName)

Добавлен в: v3.2.0
  • eventName <string> | <symbol> Имя события, за которым следят
  • Возвращает: <целое>

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

emitter.listeners(eventName)

История
Версия Изменения
v7.0.0

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

v0.1.26

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

  • eventName <строка> | <символ>
  • Возвращает: <Функция[]>

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

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

emitter.off(eventName, listener)

Добавлен в: v10.0.0
  • eventName <строка> | <символ>
  • listener <Функция>
  • Возвращает: <EventEmitter>

Псевдоним для emitter.removeListener().

emitter.on(eventName, listener)

Добавлен в: v0.1.101
  • eventName <строка> | <символ> Название события.
  • listener <Функция> Функция обратного вызова
  • Возвращает: <EventEmitter>

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

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

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

По умолчанию слушатели событий вызываются в порядке их добавления. Метод emitter.prependListener() может использоваться в качестве альтернативы для добавления слушателя события в начало массива слушателей.

const myEE = new EventEmitter();
myEE.on('foo', () => console.log('a'));
myEE.prependListener('foo', () => console.log('b'));
myEE.emit('foo');
// Prints:
//   b
//   a

emitter.once(eventName, listener)

Добавлен в: v0.3.0
  • eventName <строка> | <символ> Название события.
  • listener <Функция> Функция обратного вызова
  • Возвращает: <EventEmitter>

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

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

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

По умолчанию слушатели событий вызываются в порядке их добавления. Метод emitter.prependOnceListener() может использоваться в качестве альтернативы для добавления слушателя события в начало массива слушателей.

const myEE = new EventEmitter();
myEE.once('foo', () => console.log('a'));
myEE.prependOnceListener('foo', () => console.log('b'));
myEE.emit('foo');
// Prints:
//   b
//   a

emitter.prependListener(eventName, listener)

Добавлен в: v6.0.0
  • eventName <строка> | <символ> Название события.
  • listener <Функция> Функция обратного вызова
  • Возвращает: <EventEmitter>

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

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

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

emitter.prependOnceListener(eventName, listener)

Добавлен в: v6.0.0
  • eventName <строка> | <символ> Название события.
  • listener <Функция> Функция обратного вызова
  • Возвращает: <EventEmitter>

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

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

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

emitter.removeAllListeners([eventName])

Добавлен в: v0.1.26
  • eventName <строка> | <символ>
  • Возвращает: <EventEmitter>

Удаляет всех слушателей или тех, что указанного eventName.

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

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

emitter.removeListener(eventName, listener)

Добавлен в: v0.1.26
  • eventName <строка> | <символ>
  • listener <Функция>
  • Возвращает: <EventEmitter>

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

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

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

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

const myEmitter = new MyEmitter();

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

const 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(), потребуется пересоздать.

Когда одна функция была добавлена ​​в качестве обработчика несколько раз для одного события (как в примере ниже), removeListener() удалит последний добавленный экземпляр. В примере удаляется слушатель once('ping').

const ee = new EventEmitter();

function pong() {
  console.log('pong');
}

ee.on('ping', pong);
ee.once('ping', pong);
ee.removeListener('ping', pong);

ee.emit('ping');
ee.emit('ping');

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

emitter.setMaxListeners(n)

Добавлен в: v0.3.5
  • n <целое число>
  • Возвращает: <EventEmitter>

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

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

emitter.rawListeners(eventName)

Добавлен в: v9.4.0
  • eventName <строка> | <символ>
  • Возвращает: <Функция[]>

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

const emitter = new EventEmitter();
emitter.once('log', () => console.log('log once'));

// Returns a new Array with a function `onceWrapper` which has a property
// `listener` which contains the original listener bound above
const listeners = emitter.rawListeners('log');
const logFnWrapper = listeners[0];

// Logs "log once" to the console and does not unbind the `once` event
logFnWrapper.listener();

// Logs "log once" to the console and removes the listener
logFnWrapper();

emitter.on('log', () => console.log('log persistently'));
// Will return a new Array with a single function bound by `.on()` above
const newListeners = emitter.rawListeners('log');

// Logs "log persistently" twice
newListeners[0]();
emitter.emit('log');

emitter[Symbol.for('nodejs.rejection')](err, eventName[, ...args])

Добавлен в: v13.4.0, v12.16.0
Устойчивость: 1 - captureRejections является экспериментальной.
  • err Ошибка
  • eventName <строка> | <символ>
  • ...args <любой>

Метод Symbol.for('nodejs.rejection') вызывается в случае отмены выполнения промиса при генерации события, и если опция captureRejections включена для эмиттера. Можно использовать events.captureRejectionSymbol вместо Symbol.for('nodejs.rejection').

const { EventEmitter, captureRejectionSymbol } = require('events');

class MyClass extends EventEmitter {
  constructor() {
    super({ captureRejections: true });
  }

  [captureRejectionSymbol](err, event, ...args) {
    console.log('rejection happened for', event, 'with', err, ...args);
    this.destroy(err);
  }

  destroy(err) {
    // Tear the resource down here.
  }
}

events.getEventListeners(emitterOrTarget, eventName)

Добавлен в: v14.17.0
  • emitterOrTarget <EventEmitter> | <EventTarget>
  • eventName <строка> | <символ>
  • Возвращает: <Массив функций>

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

Для EventEmitter это работает точно так же, как вызов .listeners у эмиттера.

Для EventTarget это единственный способ получить слушателей событий для целевого объекта. Это полезно для отладки и диагностики.

const { getEventListeners, EventEmitter } = require('events');

{
  const ee = new EventEmitter();
  const listener = () => console.log('Events are fun');
  ee.on('foo', listener);
  getEventListeners(ee, 'foo'); // [listener]
}
{
  const et = new EventTarget();
  const listener = () => console.log('Events are fun');
  et.addEventListener('foo', listener);
  getEventListeners(et, 'foo'); // [listener]
}

events.once(emitter, name[, options])

Добавлен в: v11.13.0, v10.16.0
  • emitter <EventEmitter>
  • name <строка>
  • options <Объект>
    • signal <AbortSignal> Можно использовать для отмены ожидания события.
  • Возвращает: <Promise>

Создаёт Promise который выполняется, когда EventEmitter генерирует указанное событие, или отклоняется, если EventEmitter генерирует 'error' во время ожидания. Promise будет разрешён массивом всех аргументов, переданных в указанное событие.

Этот метод намеренно универсален и работает с интерфейсом web-платформы EventTarget, у которого нет специальной семантики события 'error' и не слушается события 'error'.

const { once, EventEmitter } = require('events');

async function run() {
  const ee = new EventEmitter();

  process.nextTick(() => {
    ee.emit('myevent', 42);
  });

  const [value] = await once(ee, 'myevent');
  console.log(value);

  const err = new Error('kaboom');
  process.nextTick(() => {
    ee.emit('error', err);
  });

  try {
    await once(ee, 'myevent');
  } catch (err) {
    console.log('error happened', err);
  }
}

run();

Специальная обработка события 'error' используется только тогда, когда events.once() используется для ожидания другого события. Если events.once() используется для ожидания события 'error'', тогда оно обрабатывается как любое другое событие без специальной обработки:

const { EventEmitter, once } = require('events');

const ee = new EventEmitter();

once(ee, 'error')
  .then(([err]) => console.log('ok', err.message))
  .catch((err) => console.log('error', err.message));

ee.emit('error', new Error('boom'));

// Prints: ok boom

Для отмены ожидания события можно использовать <AbortSignal>:

const { EventEmitter, once } = require('events');

const ee = new EventEmitter();
const ac = new AbortController();

async function foo(emitter, event, signal) {
  try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
  } catch (error) {
    if (error.name === 'AbortError') {
      console.error('Waiting for the event was canceled!');
    } else {
      console.error('There was an error', error.message);
    }
  }
}

foo(ee, 'foo', ac.signal);
ac.abort(); // Abort waiting for the event
ee.emit('foo'); // Prints: Waiting for the event was canceled!

Ожидание нескольких событий, генерируемых на process.nextTick()

Существует частный случай, который стоит отметить, при использовании функции events.once() для ожидания нескольких событий, генерируемых в одной группе операций process.nextTick(), или когда несколько событий генерируются синхронно. В частности, поскольку очередь process.nextTick() обрабатывается перед микроочередью Promise, и поскольку EventEmitter генерирует все события синхронно, возможно пропустить событие events.once().

const { EventEmitter, once } = require('events');

const myEE = new EventEmitter();

async function foo() {
  await once(myEE, 'bar');
  console.log('bar');

  // This Promise will never resolve because the 'foo' event will
  // have already been emitted before the Promise is created.
  await once(myEE, 'foo');
  console.log('foo');
}

process.nextTick(() => {
  myEE.emit('bar');
  myEE.emit('foo');
});

foo().then(() => console.log('done'));

Чтобы поймать оба события, создайте каждый из обещаний до ожидания любого из них, затем можно использовать Promise.all(), Promise.race(), или Promise.allSettled():

const { EventEmitter, once } = require('events');

const myEE = new EventEmitter();

async function foo() {
  await Promise.all([once(myEE, 'bar'), once(myEE, 'foo')]);
  console.log('foo', 'bar');
}

process.nextTick(() => {
  myEE.emit('bar');
  myEE.emit('foo');
});

foo().then(() => console.log('done'));

events.captureRejections

Добавлен в: v13.4.0, v12.16.0
Устойчивость: 1 - captureRejections является экспериментальной.

Значение: <логическое>

Изменить значение опции captureRejections по умолчанию для всех новых объектов EventEmitter.

events.captureRejectionSymbol

Добавлен в: v13.4.0, v12.16.0
Устойчивость: 1 - captureRejections является экспериментальной.

Значение: Symbol.for('nodejs.rejection')

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

events.on(emitter, eventName[, options])

Добавлен в: v13.6.0, v12.16.0
  • emitter <EventEmitter>
  • eventName <строка> | <символ> Имя события, на которое нужно подписаться
  • options <Объект>
    • signal <AbortSignal> Можно использовать для отмены ожидания событий.
  • Возвращает: <AsyncIterator> перебирающий eventName события, генерируемые emitter
const { on, EventEmitter } = require('events');

(async () => {
  const ee = new EventEmitter();

  // Emit later on
  process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
  });

  for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
  }
  // Unreachable here
})();

Возвращает AsyncIterator, который перебирает eventName события. Вызовет исключение, если EventEmitter генерирует 'error'. Удаляет все слушатели при выходе из цикла. value возвращённый каждой итерацией — это массив аргументов, переданных в событие.

Для отмены ожидания событий можно использовать <AbortSignal>:

const { on, EventEmitter } = require('events');
const ac = new AbortController();

(async () => {
  const ee = new EventEmitter();

  // Emit later on
  process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
  });

  for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
  }
  // Unreachable here
})();

process.nextTick(() => ac.abort());

EventTarget и Event API

Добавлен в: v14.5.0
Устойчивость: 1 - Экспериментальный

Объекты EventTarget и Event — это реализация специфичная для Node.js объекта EventTarget API веб-платформы, экспонируемая некоторыми ядрами Node.js. Классы EventTarget и Event недоступны для создания кодом конечного пользователя.

const target = getEventTargetSomehow();

target.addEventListener('foo', (event) => {
  console.log('foo event happened!');
});

Node.js EventTarget по сравнению с DOM EventTarget

Существует два ключевых отличия между Node.js EventTarget и EventTarget API веб-платформы:

  1. В то время как экземпляры DOM EventTarget могут быть иерархическими, в Node.js понятия иерархии и распространения событий нет. То есть, событие, отправленное экземпляру EventTarget, не распространяется через иерархию вложенных целевых объектов, каждый из которых может иметь свой набор обработчиков события.
  2. В Node.js EventTarget, если обработчик события является асинхронной функцией или возвращает Promise, и возвращённый Promise отклоняется, отклонение автоматически обрабатывается так же, как и обработчик, который выбрасывает исключение синхронно (подробности см. в разделе EventTarget обработки ошибок).

NodeEventTarget по сравнению с EventEmitter

Объект NodeEventTarget реализует модифицированный подмножество EventEmitter API, позволяющее ему эмулировать EventEmitter в определённых ситуациях. Объект NodeEventTarget не является экземпляром EventEmitter и не может быть использован вместо EventEmitter в большинстве случаев.

  1. В отличие от EventEmitter, любой конкретный listener может быть зарегистрирован не более чем один раз на тип события type. Попытки зарегистрировать listener несколько раз игнорируются.
  2. Объект NodeEventTarget не эмулирует полный EventEmitter API. В частности, prependListener(), prependOnceListener(), rawListeners(), setMaxListeners(), getMaxListeners() и errorMonitor API не эмулируются. События 'newListener' и 'removeListener' также не будут генерироваться.
  3. Объект NodeEventTarget не реализует никакого специального поведенния по умолчанию для событий типа 'error'.
  4. Объект NodeEventTarget поддерживает объекты EventListener и функции в качестве обработчиков для всех типов событий.

Обработчик события

Обработчики событий, зарегистрированные для события type, могут быть JavaScript-функциями или объектами с свойством handleEvent, значением которого является функция.

В любом случае, функция-обработчик вызывается с аргументом event, переданным в функцию eventTarget.dispatchEvent().

В качестве обработчиков могут использоваться асинхронные функции. Если асинхронная функция-обработчик отклоняет Promise, отклонение обрабатывается так, как описано в EventTarget обработке ошибок.

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

Возвращаемое значение функции-обработчика игнорируется.

Обработчики всегда вызываются в порядке их добавления.

Функции-обработчики могут изменять объект event.

function handler1(event) {
  console.log(event.type);  // Prints 'foo'
  event.a = 1;
}

async function handler2(event) {
  console.log(event.type);  // Prints 'foo'
  console.log(event.a);  // Prints 1
}

const handler3 = {
  handleEvent(event) {
    console.log(event.type);  // Prints 'foo'
  }
};

const handler4 = {
  async handleEvent(event) {
    console.log(event.type);  // Prints 'foo'
  }
};

const target = getEventTargetSomehow();

target.addEventListener('foo', handler1);
target.addEventListener('foo', handler2);
target.addEventListener('foo', handler3);
target.addEventListener('foo', handler4, { once: true });

EventTarget обработка ошибок

При возникновении ошибки в зарегистрированном обработчике события (или возвращении Promise, который отклоняется), по умолчанию ошибка обрабатывается как непредвиденное исключение в process.nextTick(). Это означает, что непредвиденные исключения в EventTarget по умолчанию завершат процесс Node.js.

Выброс исключения внутри обработчика события не остановит вызов других зарегистрированных обработчиков.

Объект EventTarget не реализует никакого специального поведенния по умолчанию для событий типа 'error', таких как EventEmitter.

В настоящее время ошибки сначала передаются событию process.on('error') прежде, чем достигнут process.on('uncaughtException'). Это поведение устарело и изменится в будущих версиях, чтобы привести EventTarget в соответствие с другими API Node.js. Любой код, полагающийся на событие process.on('error'), должен быть приведен в соответствие с новым поведением.

Класс: Event

Добавлен в: v14.5.0

Объект Event — это адаптация Event API веб-платформы. Экземпляры создаются внутри Node.js.

event.bubbles
Добавлен в: v14.5.0
  • Тип: <boolean> Всегда возвращает false.

В Node.js не используется и предоставлен только для полноты.

event.cancelBubble()
Добавлен в: v14.5.0

Псевдоним для event.stopPropagation(). В Node.js не используется и предоставлен только для полноты.

event.cancelable
Добавлен в: v14.5.0
  • Тип: <boolean> Истинно, если событие было создано с опцией cancelable.
event.composed
Добавлен в: v14.5.0
  • Тип: <boolean> Всегда возвращает false.

В Node.js не используется и предоставлен только для полноты.

event.composedPath()
Добавлен в: v14.5.0

Возвращает массив, содержащий текущий EventTarget в качестве единственного элемента или пустой массив, если событие не отправляется. В Node.js не используется и предоставлен только для полноты.

event.currentTarget
Добавлен в: v14.5.0
  • Тип: <EventTarget> EventTarget отправляющее событие.

Псевдоним для event.target.

event.defaultPrevented
Добавлен в: v14.5.0
  • Тип: <boolean>

Истинно, если cancelable является true и event.preventDefault() был вызван.

event.eventPhase
Добавлен в: v14.5.0
  • Тип: <number> Возвращает 0 пока событие не отправляется, 2 во время отправки.

В Node.js не используется и предоставлен только для полноты.

event.isTrusted
Добавлен в: v14.5.0
  • Тип: <boolean> Истинно для внутренних событий Node.js, ложно в противном случае.

В настоящее время только событие AbortSignal объекта "abort" генерируется с isTrusted установленным в true.

event.preventDefault()
Добавлен в: v14.5.0

Устанавливает свойство defaultPrevented в true если cancelable является true.

event.returnValue
Добавлен в: v14.5.0
  • Тип: <boolean> Истинно, если событие не отменено.

В Node.js не используется и предоставлен только для полноты.

event.srcElement
Добавлен в: v14.5.0
  • Тип: <EventTarget> EventTarget отправляющее событие.

Псевдоним для event.target.

event.stopImmediatePropagation()
Добавлен в: v14.5.0

Останавливает вызов обработчиков событий после завершения текущего.

event.stopPropagation()
Добавлен в: v14.5.0

В Node.js не используется и предоставлен только для полноты.

event.target
Добавлен в: v14.5.0
  • Тип: <EventTarget> EventTarget отправляющее событие.
event.timeStamp
Добавлен в: v14.5.0
  • Тип: <number>

Маркер времени (в миллисекундах) создания объекта Event.

event.type
Добавлен в: v14.5.0
  • Тип: <string>

Идентификатор типа события.

Класс: EventTarget

Добавлен в: v14.5.0
eventTarget.addEventListener(type, listener[, options])
Добавлен в: v14.5.0
  • type <строка>
  • listener <Функция> | <Обработчик события>
  • options <Объект>
    • once <булево> Когда true, обработчик автоматически удаляется при первом вызове. По умолчанию: false.
    • passive <булево> Когда true, служит подсказкой, что обработчик не будет вызывать метод Event объекта preventDefault(). По умолчанию: false.
    • capture <булево> Не используется напрямую Node.js. Добавлено для полноты API. По умолчанию: false.

Добавляет новый обработчик для события type. Любой заданный listener добавляется только один раз на один type и на одно значение capture опции.

Если опция once имеет значение true, обработчик listener удаляется после следующего срабатывания события type.

Опция capture не используется Node.js функционально, кроме отслеживания зарегистрированных обработчиков событий в соответствии со спецификацией EventTarget. В частности, опция capture используется в качестве части ключа при регистрации listener. Любой отдельный listener может быть добавлен один раз с capture = false, и один раз с capture = true.

function handler(event) {}

const target = getEventTargetSomehow();
target.addEventListener('foo', handler, { capture: true });  // first
target.addEventListener('foo', handler, { capture: false }); // second

// Removes the second instance of handler
target.removeEventListener('foo', handler);

// Removes the first instance of handler
target.removeEventListener('foo', handler, { capture: true });
eventTarget.dispatchEvent(event)
Добавлен в: v14.5.0
  • event <Объект> | <Событие>

Отправляет событие event в список обработчиков для event.type. Событие event может быть объектом Event или любым объектом со свойством type, значение которого — string.

Зарегистрированные обработчики событий вызываются синхронно в порядке их регистрации.

eventTarget.removeEventListener(type, listener)
Добавлен в: v14.5.0
  • type <строка>
  • listener <Функция> | <Обработчик события>
  • options <Объект>
    • capture <булево>

Удаляет listener из списка обработчиков события type.

Класс: NodeEventTarget

Добавлен в: v14.5.0
  • Расширяет: <EventTarget>

NodeEventTarget — расширение Node.js для EventTarget, эмулирующее подмножество API EventEmitter.

nodeEventTarget.addListener(type, listener[, options])
Добавлен в: v14.5.0
  • type <строка>

  • listener <Функция> | <Обработчик события>

  • options <Объект>

    • once <булево>
  • Возвращает: <EventTarget> this

Уникальное для Node.js расширение класса EventTarget, которое эмулирует эквивалентный API EventEmitter . Единственное различие между addListener() и addEventListener() в том, что addListener() вернёт ссылку на EventTarget.

nodeEventTarget.eventNames()
Добавлен в: v14.5.0
  • Возвращает: <массив строк>

Уникальное для Node.js расширение класса EventTarget, которое возвращает массив имён событий type, для которых зарегистрированы обработчики.

nodeEventTarget.listenerCount(type)
Добавлен в: v14.5.0
  • type <строка>

  • Возвращает: <число>

Уникальное для Node.js расширение класса EventTarget, которое возвращает количество обработчиков событий, зарегистрированных для type.

nodeEventTarget.off(type, listener)
Добавлен в: v14.5.0
  • type <строка>

  • listener <Функция> | <Обработчик события>

  • Возвращает: <EventTarget> this

Уникальный для Node.js псевдоним для eventTarget.removeListener().

nodeEventTarget.on(type, listener[, options])
Добавлен в: v14.5.0
  • type <строка>

  • listener <Функция> | <Обработчик события>

  • options <Объект>

    • once <булево>
  • Возвращает: <EventTarget> this

Уникальный для Node.js псевдоним для eventTarget.addListener().

nodeEventTarget.once(type, listener[, options])
Добавлен в: v14.5.0
  • type <строка>

  • listener <Функция> | <Обработчик события>

  • options <Объект>

  • Возвращает: <EventTarget> this

Уникальное для Node.js расширение класса EventTarget, которое добавляет обработчик события once для заданного события type. Это эквивалентно вызову on с опцией once установленной в true.

nodeEventTarget.removeAllListeners([type])
Добавлен в: v14.5.0
  • type <строка>

  • Возвращает: <EventTarget> this

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

nodeEventTarget.removeListener(type, listener)
Добавлен в: v14.5.0
  • type <строка>

  • listener <Функция> | <Обработчик события>

  • Возвращает: <EventTarget> this

Уникальное для Node.js расширение класса EventTarget, которое удаляет listener для данного type. Единственное различие между removeListener() и removeEventListener() в том, что removeListener() вернёт ссылку на EventTarget.

© 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-v14.x/docs/api/events.html

Spec-Zone.ru

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