Spec-Zone.ru › Node.js

События

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

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

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

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

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

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

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

Модули JavaScript
import { EventEmitter } from 'node:events';

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});
myEmitter.emit('event');
CommonJS
const EventEmitter = require('node: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, к которому привязан слушатель.

Модули JavaScript
import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', function(a, b) {
  console.log(a, b, this, this === myEmitter);
  // Prints:
  //   a b MyEmitter {
  //     _events: [Object: null prototype] { event: [Function (anonymous)] },
  //     _eventsCount: 1,
  //     _maxListeners: undefined,
  //     Symbol(shapeMode): false,
  //     Symbol(kCapture): false
  //   } true
});
myEmitter.emit('event', 'a', 'b');
CommonJS
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', function(a, b) {
  console.log(a, b, this, this === myEmitter);
  // Prints:
  //   a b MyEmitter {
  //     _events: [Object: null prototype] { event: [Function (anonymous)] },
  //     _eventsCount: 1,
  //     _maxListeners: undefined,
  //     Symbol(shapeMode): false,
  //     Symbol(kCapture): false
  //   } true
});
myEmitter.emit('event', 'a', 'b');

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

Модули JavaScript
import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  console.log(a, b, this);
  // Prints: a b undefined
});
myEmitter.emit('event', 'a', 'b');
CommonJS
const EventEmitter = require('node:events');
class MyEmitter extends 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():

Модули JavaScript
import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  setImmediate(() => {
    console.log('this happens asynchronously');
  });
});
myEmitter.emit('event', 'a', 'b');
CommonJS
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  setImmediate(() => {
    console.log('this happens asynchronously');
  });
});
myEmitter.emit('event', 'a', 'b');

Однократная обработка событий

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

Модули JavaScript
import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.on('event', () => {
  console.log(++m);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Prints: 2
CommonJS
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
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() можно зарегистрировать слушатель, который будет вызван не более одного раза для определённого события. После генерации события слушатель снимается с регистрации, а затем вызывается.

Модули JavaScript
import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.once('event', () => {
  console.log(++m);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Ignored
CommonJS
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
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 завершается.

Модули JavaScript
import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));
// Throws and crashes Node.js
CommonJS
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));
// Throws and crashes Node.js

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

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

Модули JavaScript
import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
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
CommonJS
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
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' можно отслеживать, не обрабатывая сгенерированную ошибку, установив слушатель с помощью символа events.errorMonitor.

Модули JavaScript
import { EventEmitter, errorMonitor } from 'node:events';

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

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

Перехват отклонений промисов

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

Модули JavaScript
import { EventEmitter } from 'node:events';
const ee = new EventEmitter();
ee.on('something', async (value) => {
  throw new Error('kaboom');
});
CommonJS
const EventEmitter = require('node:events');
const ee = new EventEmitter();
ee.on('something', async (value) => {
  throw new Error('kaboom');
});

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

Модули JavaScript
import { EventEmitter } from 'node:events';
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;
CommonJS
const EventEmitter = require('node:events');
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;

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

Модули JavaScript
import { EventEmitter } from 'node:events';

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

ee1.on('error', console.log);
CommonJS
const events = require('node:events');
events.captureRejections = true;
const ee1 = new events.EventEmitter();
ee1.on('something', async (value) => {
  throw new Error('kaboom');
});

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

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

Класс: EventEmitter

Добавлено в: v0.1.26
История
Версия Изменения
v13.4.0, v12.16.0

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

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

Модули JavaScript
import { EventEmitter } from 'node:events';
CommonJS
const EventEmitter = require('node:events');

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

Поддерживается следующий параметр:

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

Событие: 'newListener'

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

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

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

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

Модули JavaScript
import { EventEmitter } from 'node:events';
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
CommonJS
const EventEmitter = require('node:events');
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'

Добавлено в: v0.9.3
История
Версия Изменения
v6.1.0, v4.7.0

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

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

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

emitter.addListener(eventName, listener)

Добавлено в: v0.1.26
  • eventName <string> | <symbol>
  • listener <Function>

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

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

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

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

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

Модули JavaScript
import { EventEmitter } from 'node: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
CommonJS
const EventEmitter = require('node: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
  • Возвращает: <string[]> | <symbol[]>

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

Модули JavaScript
import { EventEmitter } from 'node: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) ]
CommonJS
const EventEmitter = require('node: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
  • Возвращает: <integer>

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

emitter.listenerCount(eventName[, listener])

Добавлено в: v3.2.0
История
Версия Изменения
v19.8.0, v18.16.0

Добавлен аргумент listener.

  • eventName <string> | <symbol> Имя отслеживаемого события
  • listener <Function> Функция-обработчик события
  • Возвращает: <integer>

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

emitter.listeners(eventName)

Добавлено в: v0.1.26
История
Версия Изменения
v7.0.0

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

  • eventName <string> | <symbol>
  • Возвращает: <Function[]>

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

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

emitter.off(eventName, listener)

Добавлено в: v10.0.0
  • eventName <string> | <symbol>
  • listener <Function>
  • Возвращает: <EventEmitter>

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

emitter.on(eventName, listener)

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

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

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

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

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

Модули JavaScript
import { EventEmitter } from 'node:events';
const myEE = new EventEmitter();
myEE.on('foo', () => console.log('a'));
myEE.prependListener('foo', () => console.log('b'));
myEE.emit('foo');
// Prints:
//   b
//   a
CommonJS
const EventEmitter = require('node:events');
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 <string> | <symbol> Имя события.
  • listener <Function> Функция обратного вызова
  • Возвращает: <EventEmitter>

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

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

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

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

Модули JavaScript
import { EventEmitter } from 'node:events';
const myEE = new EventEmitter();
myEE.once('foo', () => console.log('a'));
myEE.prependOnceListener('foo', () => console.log('b'));
myEE.emit('foo');
// Prints:
//   b
//   a
CommonJS
const EventEmitter = require('node:events');
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 <string> | <symbol> Имя события.
  • listener <Function> Функция обратного вызова
  • Возвращает: <EventEmitter>

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

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

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

emitter.prependOnceListener(eventName, listener)

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

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

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

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

emitter.removeAllListeners([eventName])

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

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

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

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

emitter.removeListener(eventName, listener)

Добавлено в: v0.1.26
  • eventName <string> | <symbol>
  • listener <Function>
  • Возвращает: <EventEmitter>

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

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

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

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

Модули JavaScript
import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
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
CommonJS
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
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'):

Модули JavaScript
import { EventEmitter } from 'node:events';
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');
CommonJS
const EventEmitter = require('node:events');
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 <integer>
  • Возвращает: <EventEmitter>

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

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

emitter.rawListeners(eventName)

Добавлено в: v9.4.0
  • eventName <string> | <symbol>
  • Возвращает: <Function[]>

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

Модули JavaScript
import { EventEmitter } from 'node:events';
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');
CommonJS
const EventEmitter = require('node:events');
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
История
Версия Изменения
v17.4.0, v16.14.0

Больше не является экспериментальным.

  • err <Error>
  • eventName <string> | <symbol>
  • ...args <any>

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

Модули JavaScript
import { EventEmitter, captureRejectionSymbol } from 'node: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.
  }
}
CommonJS
const { EventEmitter, captureRejectionSymbol } = require('node: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.defaultMaxListeners

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

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

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

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

defaultMaxListeners не влияет на экземпляры AbortSignal. Хотя для отдельных экземпляров AbortSignal по-прежнему можно задать предел предупреждений с помощью emitter.setMaxListeners(n), экземпляры AbortSignal по умолчанию не выдают предупреждений.

Модули JavaScript
import { EventEmitter } from 'node:events';
const emitter = new EventEmitter();
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
emitter.once('event', () => {
  // do stuff
  emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
});
CommonJS
const EventEmitter = require('node:events');
const emitter = new EventEmitter();
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'.

events.errorMonitor

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

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

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

events.getEventListeners(emitterOrTarget, eventName)

Добавлено в: v15.2.0, v14.17.0
  • emitterOrTarget <EventEmitter> | <EventTarget>
  • eventName <string> | <symbol>
  • Возвращает: <Function[]>

Возвращает копию массива обработчиков события с именем eventName.

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

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

Модули JavaScript
import { getEventListeners, EventEmitter } from 'node:events';

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

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

events.getMaxListeners(emitterOrTarget)

Добавлено в: v19.9.0, v18.17.0
  • emitterOrTarget <EventEmitter> | <EventTarget>
  • Возвращает: <number>

Возвращает текущее установленное максимальное количество обработчиков.

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

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

Модули JavaScript
import { getMaxListeners, setMaxListeners, EventEmitter } from 'node:events';

{
  const ee = new EventEmitter();
  console.log(getMaxListeners(ee)); // 10
  setMaxListeners(11, ee);
  console.log(getMaxListeners(ee)); // 11
}
{
  const et = new EventTarget();
  console.log(getMaxListeners(et)); // 10
  setMaxListeners(11, et);
  console.log(getMaxListeners(et)); // 11
}
CommonJS
const { getMaxListeners, setMaxListeners, EventEmitter } = require('node:events');

{
  const ee = new EventEmitter();
  console.log(getMaxListeners(ee)); // 10
  setMaxListeners(11, ee);
  console.log(getMaxListeners(ee)); // 11
}
{
  const et = new EventTarget();
  console.log(getMaxListeners(et)); // 10
  setMaxListeners(11, et);
  console.log(getMaxListeners(et)); // 11
}

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

Добавлено в: v11.13.0, v10.16.0
История
Версия Изменения
v15.0.0

Теперь поддерживается параметр signal.

  • emitter <EventEmitter>
  • name <string> | <symbol>
  • options <Object>
    • signal <AbortSignal> Можно использовать для отмены ожидания события.
  • Возвращает: <Promise>

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

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

Модули JavaScript
import { once, EventEmitter } from 'node:events';
import process from 'node:process';

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.error('error happened', err);
}
CommonJS
const { once, EventEmitter } = require('node: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.error('error happened', err);
  }
}

run();

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

Модули JavaScript
import { EventEmitter, once } from 'node:events';

const ee = new EventEmitter();

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

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

// Prints: ok boom
CommonJS
const { EventEmitter, once } = require('node:events');

const ee = new EventEmitter();

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

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

// Prints: ok boom

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

Модули JavaScript
import { EventEmitter, once } from 'node: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(); // Prints: Waiting for the event was canceled!
CommonJS
const { EventEmitter, once } = require('node: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(); // Prints: Waiting for the event was canceled!

Особенности ожидания нескольких событий

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

Обычные обработчики событий вызываются синхронно при генерации события. Это гарантирует, что выполнение не продолжится после сгенерированного события, пока не завершат работу все обработчики.

При ожидании промисов, возвращаемых events.once(), это не так. Задачи промисов обрабатываются только после завершения текущего стека вызовов, а значит, несколько событий могут быть сгенерированы до того, как асинхронное выполнение продолжится после соответствующего оператора await.

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

Модули JavaScript
import { EventEmitter, once } from 'node:events';
import process from 'node:process';

const myEE = new EventEmitter();

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

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

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

listen().then(() => console.log('done'));
CommonJS
const { EventEmitter, once } = require('node:events');

const myEE = new EventEmitter();

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

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

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

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

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

Модули JavaScript
import { EventEmitter, once } from 'node:events';
import process from 'node:process';

const myEE = new EventEmitter();

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

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

listen().then(() => console.log('done'));
CommonJS
const { EventEmitter, once } = require('node:events');

const myEE = new EventEmitter();

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

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

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

events.captureRejections

Добавлено в: v13.4.0, v12.16.0
История
Версия Изменения
v17.4.0, v16.14.0

Больше не является экспериментальным.

  • Тип: <boolean>

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

events.captureRejectionSymbol

Добавлено в: v13.4.0, v12.16.0
История
Версия Изменения
v17.4.0, v16.14.0

Больше не является экспериментальным.

  • Тип: <symbol> Symbol.for('nodejs.rejection')

См. инструкции по написанию пользовательского обработчика отклонений.

events.listenerCount(emitterOrTarget, eventName)

Добавлено в: v0.9.12
История
Версия Изменения
v25.4.0, v24.14.0

Теперь принимает аргументы EventTarget.

v25.4.0, v24.14.0

Отмена устаревания.

v3.2.0

Устаревание только в документации.

  • emitterOrTarget <EventEmitter> | <EventTarget>
  • eventName <string> | <symbol>
  • Возвращает: <integer>

Возвращает количество зарегистрированных обработчиков события с именем eventName.

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

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

Модули JavaScript
import { EventEmitter, listenerCount } from 'node:events';

{
  const ee = new EventEmitter();
  ee.on('event', () => {});
  ee.on('event', () => {});
  console.log(listenerCount(ee, 'event')); // 2
}
{
  const et = new EventTarget();
  et.addEventListener('event', () => {});
  et.addEventListener('event', () => {});
  console.log(listenerCount(et, 'event')); // 2
}
CommonJS
const { EventEmitter, listenerCount } = require('node:events');

{
  const ee = new EventEmitter();
  ee.on('event', () => {});
  ee.on('event', () => {});
  console.log(listenerCount(ee, 'event')); // 2
}
{
  const et = new EventTarget();
  et.addEventListener('event', () => {});
  et.addEventListener('event', () => {});
  console.log(listenerCount(et, 'event')); // 2
}

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

Добавлено в: v13.6.0, v12.16.0
История
Версия Изменения
v22.0.0, v20.13.0

Для согласованности поддерживаются параметры highWaterMark и lowWaterMark. Старые параметры по-прежнему поддерживаются.

v20.0.0

Теперь поддерживаются параметры close, highWatermark и lowWatermark.

  • emitter <EventEmitter>
  • eventName <string> | <symbol> Имя прослушиваемого события
  • options <Object>
    • signal <AbortSignal> Можно использовать для отмены ожидания событий.
    • close <string[]> Имена событий, которые завершат итерацию.
    • highWaterMark <integer> По умолчанию: Number.MAX_SAFE_INTEGER Верхний порог. Эмиттер приостанавливается каждый раз, когда количество буферизованных событий превышает это значение. Поддерживается только эмиттерами, реализующими методы pause() и resume().
    • lowWaterMark <integer> По умолчанию: 1 Нижний порог. Эмиттер возобновляет работу каждый раз, когда количество буферизованных событий становится меньше этого значения. Поддерживается только эмиттерами, реализующими методы pause() и resume().
  • Возвращает: <AsyncIterator>, который перебирает события eventName, сгенерированные emitter
Модули JavaScript
import { on, EventEmitter } from 'node:events';
import process from 'node:process';

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
CommonJS
const { on, EventEmitter } = require('node: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>:

Модули JavaScript
import { on, EventEmitter } from 'node:events';
import process from 'node:process';

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());
CommonJS
const { on, EventEmitter } = require('node: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());

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

Добавлено в: v15.4.0
  • n <number> Неотрицательное число. Максимальное количество обработчиков для события EventTarget.
  • ...eventsTargets <EventTarget[]> | <EventEmitter[]> Ноль или более экземпляров <EventTarget> или <EventEmitter>. Если экземпляры не указаны, n задаётся в качестве максимального значения по умолчанию для всех вновь созданных объектов <EventTarget> и <EventEmitter>.
Модули JavaScript
import { setMaxListeners, EventEmitter } from 'node:events';

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

setMaxListeners(5, target, emitter);
CommonJS
const {
  setMaxListeners,
  EventEmitter,
} = require('node:events');

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

setMaxListeners(5, target, emitter);

events.addAbortListener(signal, listener)

Добавлено в: v20.5.0, v18.18.0
История
Версия Изменения
v24.0.0, v22.16.0

Уровень стабильности этой функции изменён с «Экспериментальный» на «Стабильный».

  • signal <AbortSignal>
  • listener <Function> | <EventListener>
  • Возвращает: <Disposable> Объект Disposable, удаляющий обработчик abort.

Однократно прослушивает событие abort в переданном signal.

Прослушивание события abort у сигналов отмены небезопасно и может привести к утечкам ресурсов, поскольку другая сторона, использующая сигнал, может вызвать e.stopImmediatePropagation(). К сожалению, Node.js не может изменить это поведение, поскольку оно нарушило бы веб-стандарт. Кроме того, исходный API позволяет легко забыть удалить обработчики.

Этот API позволяет безопасно использовать AbortSignal в API Node.js, решая обе эти проблемы: обработчик события устанавливается таким образом, что stopImmediatePropagation не препятствует его вызову.

Возвращается объект Disposable, упрощающий отмену подписки.

CommonJS
const { addAbortListener } = require('node:events');

function example(signal) {
  signal.addEventListener('abort', (e) => e.stopImmediatePropagation());
  // addAbortListener() returns a disposable, so the `using` keyword ensures
  // the abort listener is automatically removed when this scope exits.
  using _ = addAbortListener(signal, (e) => {
    // Do something when signal is aborted.
  });
}
Модули JavaScript
import { addAbortListener } from 'node:events';

function example(signal) {
  signal.addEventListener('abort', (e) => e.stopImmediatePropagation());
  // addAbortListener() returns a disposable, so the `using` keyword ensures
  // the abort listener is automatically removed when this scope exits.
  using _ = addAbortListener(signal, (e) => {
    // Do something when signal is aborted.
  });
}

Класс: events.EventEmitterAsyncResource extends EventEmitter

Добавлено в: v17.4.0, v16.14.0

Интегрирует EventEmitter с <AsyncResource> для объектов EventEmitter, требующих ручного отслеживания асинхронных операций. В частности, все события, сгенерированные экземплярами events.EventEmitterAsyncResource, будут выполняться в их асинхронном контексте.

Модули JavaScript
import { EventEmitterAsyncResource, EventEmitter } from 'node:events';
import { notStrictEqual, strictEqual } from 'node:assert';
import { executionAsyncId, triggerAsyncId } from 'node:async_hooks';

// Async tracking tooling will identify this as 'Q'.
const ee1 = new EventEmitterAsyncResource({ name: 'Q' });

// 'foo' listeners will run in the EventEmitters async context.
ee1.on('foo', () => {
  strictEqual(executionAsyncId(), ee1.asyncId);
  strictEqual(triggerAsyncId(), ee1.triggerAsyncId);
});

const ee2 = new EventEmitter();

// 'foo' listeners on ordinary EventEmitters that do not track async
// context, however, run in the same async context as the emit().
ee2.on('foo', () => {
  notStrictEqual(executionAsyncId(), ee2.asyncId);
  notStrictEqual(triggerAsyncId(), ee2.triggerAsyncId);
});

Promise.resolve().then(() => {
  ee1.emit('foo');
  ee2.emit('foo');
});
CommonJS
const { EventEmitterAsyncResource, EventEmitter } = require('node:events');
const { notStrictEqual, strictEqual } = require('node:assert');
const { executionAsyncId, triggerAsyncId } = require('node:async_hooks');

// Async tracking tooling will identify this as 'Q'.
const ee1 = new EventEmitterAsyncResource({ name: 'Q' });

// 'foo' listeners will run in the EventEmitters async context.
ee1.on('foo', () => {
  strictEqual(executionAsyncId(), ee1.asyncId);
  strictEqual(triggerAsyncId(), ee1.triggerAsyncId);
});

const ee2 = new EventEmitter();

// 'foo' listeners on ordinary EventEmitters that do not track async
// context, however, run in the same async context as the emit().
ee2.on('foo', () => {
  notStrictEqual(executionAsyncId(), ee2.asyncId);
  notStrictEqual(triggerAsyncId(), ee2.triggerAsyncId);
});

Promise.resolve().then(() => {
  ee1.emit('foo');
  ee2.emit('foo');
});

Класс EventEmitterAsyncResource имеет те же методы и принимает те же параметры, что и сами EventEmitter и AsyncResource.

new events.EventEmitterAsyncResource([options])

  • options <Object>
    • captureRejections <boolean> Включает автоматический перехват отклонений промисов. По умолчанию: false.
    • name <string> Тип асинхронного события. По умолчанию: new.target.name.
    • triggerAsyncId <number> Идентификатор контекста выполнения, в котором было создано это асинхронное событие. По умолчанию: executionAsyncId().
    • requireManualDestroy <boolean> Если задано значение true, отключает emitDestroy при сборке объекта сборщиком мусора. Обычно это не требуется (даже если emitDestroy вызван вручную), за исключением случаев, когда получено значение asyncId ресурса и с ним вызван emitDestroy чувствительного API. Если задано значение false, вызов emitDestroy при сборке мусора будет выполнен только при наличии хотя бы одного активного хука destroy. По умолчанию: false.

eventemitterasyncresource.asyncId

  • Тип: <number> Уникальный asyncId, присвоенный ресурсу.

eventemitterasyncresource.asyncResource

  • Тип: <AsyncResource> Базовый объект <AsyncResource>.

Возвращённый объект AsyncResource имеет дополнительное свойство eventEmitter, которое содержит ссылку на этот EventEmitterAsyncResource.

eventemitterasyncresource.emitDestroy()

Вызывает все хуки destroy. Этот метод следует вызывать только один раз. При повторном вызове будет выброшена ошибка. Его необходимо вызывать вручную. Если ресурс будет собран сборщиком мусора, хуки destroy вызваны не будут.

eventemitterasyncresource.triggerAsyncId

  • Тип: <number> Тот же triggerAsyncId, который передаётся конструктору AsyncResource.

EventTarget и API Event

Добавлено в: v14.5.0
История
Версия Изменения
v16.0.0

Изменена обработка ошибок EventTarget.

v15.4.0

Больше не является экспериментальным.

v15.0.0

Классы EventTarget и Event теперь доступны как глобальные объекты.

Объекты EventTarget и Event представляют собой специфичную для Node.js реализацию веб-API EventTarget, доступную в некоторых основных API Node.js.

const target = new EventTarget();

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

Node.js EventTarget и DOM EventTarget

Между Node.js EventTarget и веб-API EventTarget есть два ключевых различия:

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

NodeEventTarget и EventEmitter

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

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

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

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

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

В качестве обработчиков событий можно использовать асинхронные функции. Если асинхронная функция-обработчик отклоняется, это отклонение перехватывается и обрабатывается, как описано в разделе об обработке ошибок 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 = new EventTarget();

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

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

Если зарегистрированный обработчик события выбрасывает исключение (или возвращает отклонённый промис), по умолчанию ошибка рассматривается как необработанное исключение в 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
История
Версия Изменения
v15.0.0

Класс Event теперь доступен через глобальный объект.

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

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

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

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

Стабильность: 3 — устаревшее: вместо него используйте event.stopPropagation().

  • Тип: <boolean>

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

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

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

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

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

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

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

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

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

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

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

event.initEvent(type[, bubbles[, cancelable]])
Добавлено в: v19.5.0

Стабильность: 3 — устаревшее: спецификация WHATWG считает это устаревшим, и пользователям не следует использовать это вообще.

  • type <string>
  • bubbles <boolean>
  • cancelable <boolean>

Избыточен при наличии конструкторов событий и не позволяет установить composed. В Node.js это свойство не используется и предоставлено исключительно для полноты реализации.

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

Событие <AbortSignal> "abort" создаётся со значением true для isTrusted. Во всех остальных случаях значение равно false.

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

Устанавливает свойство defaultPrevented в значение true, если cancelable имеет значение true.

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

Стабильность: 3 — устаревшее: вместо этого используйте event.defaultPrevented.

  • Тип: <boolean> Значение True, если событие не было отменено.

Значение event.returnValue всегда противоположно значению event.defaultPrevented. В Node.js это свойство не используется и предоставлено исключительно для полноты реализации.

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

Стабильность: 3 — устаревшее: вместо этого используйте event.target.

  • Тип: <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
История
Версия Изменения
v15.0.0

Класс EventTarget теперь доступен через глобальный объект.

eventTarget.addEventListener(type, listener[, options])
Добавлено в: v14.5.0
История
Версия Изменения
v15.4.0

добавлена поддержка параметра signal.

  • type <string>
  • listener <Function> | <EventListener>
  • options <Object>
    • once <boolean> Если true, обработчик автоматически удаляется при первом вызове. По умолчанию: false.
    • passive <boolean> Если true, служит подсказкой о том, что обработчик не будет вызывать метод preventDefault() объекта Event. По умолчанию: false.
    • capture <boolean> Непосредственно Node.js не использует. Добавлено для полноты API. По умолчанию: false.
    • signal <AbortSignal> Обработчик будет удалён при вызове метода abort() указанного объекта AbortSignal.

Добавляет новый обработчик события type. Каждый указанный listener добавляется только один раз для каждой пары type и значения параметра capture.

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

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

function handler(event) {}

const target = new EventTarget();
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 });
jscopy
eventTarget.dispatchEvent(event)
Добавлено в: v14.5.0
  • event <Event>
  • Возвращает: <boolean> true, если значение атрибута cancelable события равно false или его метод preventDefault() не был вызван; в противном случае — false.

Отправляет event списку обработчиков для event.type.

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

eventTarget.removeEventListener(type, listener[, options])
Добавлено в: v14.5.0
  • type <string>
  • listener <Function> | <EventListener>
  • options <Object>
    • capture <boolean>

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

Класс: CustomEvent

Добавлено в: v18.7.0, v16.17.0
История
Версия Изменения
v23.0.0

Больше не является экспериментальным.

v22.1.0, v20.13.0

CustomEvent теперь имеет стабильный статус.

v19.0.0

Больше не требует флага CLI --experimental-global-customevent.

  • Расширяет: <Event>

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

event.detail
Добавлено в: v18.7.0, v16.17.0
История
Версия Изменения
v22.1.0, v20.13.0

CustomEvent теперь имеет стабильный статус.

  • Тип: <any> Возвращает пользовательские данные, переданные при инициализации.

Только для чтения.

Класс: NodeEventTarget

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

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

nodeEventTarget.addListener(type, listener)
Добавлено в: v14.5.0
  • type <string>

  • listener <Function> | <EventListener>

  • Возвращает: <EventTarget> этот объект

Специфичное для Node.js расширение класса EventTarget, эмулирующее соответствующий API EventEmitter. Единственное различие между addListener() и addEventListener() заключается в том, что addListener() возвращает ссылку на EventTarget.

nodeEventTarget.emit(type, arg)
Добавлено в: v15.2.0
  • type <string>
  • arg <any>
  • Возвращает: <boolean> true, если для type зарегистрированы обработчики событий; в противном случае — false.

Специфичное для Node.js расширение класса EventTarget, отправляющее arg списку обработчиков для type.

nodeEventTarget.eventNames()
Добавлено в: v14.5.0
  • Возвращает: <string[]>

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

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

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

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

nodeEventTarget.setMaxListeners(n)
Добавлено в: v14.5.0
  • n <number>

Специфичное для Node.js расширение класса EventTarget, устанавливающее максимальное число обработчиков событий равным n.

nodeEventTarget.getMaxListeners()
Добавлено в: v14.5.0
  • Возвращает: <number>

Специфичное для Node.js расширение класса EventTarget, возвращающее максимальное число обработчиков событий.

nodeEventTarget.off(type, listener[, options])
Добавлено в: v14.5.0
  • type <string>

  • listener <Function> | <EventListener>

  • options <Object>

    • capture <boolean>
  • Возвращает: <EventTarget> этот объект

Специфичный для Node.js псевдоним для eventTarget.removeEventListener().

nodeEventTarget.on(type, listener)
Добавлено в: v14.5.0
  • type <string>

  • listener <Function> | <EventListener>

  • Возвращает: <EventTarget> этот объект

Специфичный для Node.js псевдоним для eventTarget.addEventListener().

nodeEventTarget.once(type, listener)
Добавлено в: v14.5.0
  • type <string>

  • listener <Function> | <EventListener>

  • Возвращает: <EventTarget> этот объект

Специфичное для Node.js расширение класса EventTarget, добавляющее обработчик once для указанного события type. Эквивалентно вызову on со значением true для параметра once.

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

  • Возвращает: <EventTarget> этот объект

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

nodeEventTarget.removeListener(type, listener[, options])
Добавлено в: v14.5.0
  • type <string>

  • listener <Function> | <EventListener>

  • options <Object>

    • capture <boolean>
  • Возвращает: <EventTarget> этот объект

Специфичное для 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/api/events.html

Spec-Zone.ru

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