События
Исходный код: lib/events.js
Значительная часть основного 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: 2CommonJS
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');
// IgnoredCommonJS
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.jsCommonJS
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 errorCommonJS
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.jsCommonJS
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
Класс EventEmitter определён и предоставляется модулем node:events:
Модули JavaScript
import { EventEmitter } from 'node:events';CommonJS
const EventEmitter = require('node:events');Все объекты EventEmitter генерируют событие 'newListener' при добавлении новых слушателей и событие 'removeListener' при удалении существующих слушателей.
Поддерживается следующий параметр:
-
captureRejections<boolean> Включает автоматический перехват отклонений промисов. По умолчанию:false.
Событие: 'newListener'
-
eventName<string> | <symbol> Имя отслеживаемого события -
listener<Function> Функция-обработчик события
Экземпляр EventEmitter генерирует собственное событие 'newListener' до добавления слушателя во внутренний массив слушателей.
Слушателям, зарегистрированным для события 'newListener', передаются имя события и ссылка на добавляемый слушатель.
Тот факт, что событие вызывается до добавления слушателя, имеет тонкое, но важное побочное следствие: любые дополнительные слушатели, зарегистрированные для того же name внутри обратного вызова '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
// ACommonJS
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'
-
eventName<string> | <symbol> Имя события -
listener<Function> Функция-обработчик события
Событие 'removeListener' генерируется после удаления listener.
emitter.addListener(eventName, listener)
-
eventName<string> | <symbol> -
listener<Function>
Псевдоним для emitter.on(eventName, listener).
emitter.emit(eventName[, ...args])
Синхронно вызывает каждый из слушателей, зарегистрированных для события с именем 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 listenerCommonJS
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()
- Возвращает: <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()
- Возвращает: <integer>
Возвращает текущее максимальное количество слушателей для EventEmitter, установленное с помощью emitter.setMaxListeners(n) или равное значению по умолчанию events.defaultMaxListeners.
emitter.listenerCount(eventName[, listener])
-
eventName<string> | <symbol> Имя отслеживаемого события -
listener<Function> Функция-обработчик события - Возвращает: <integer>
Возвращает количество слушателей, отслеживающих событие с именем eventName. Если указан listener, возвращается количество его вхождений в список слушателей события.
emitter.listeners(eventName)
-
eventName<string> | <symbol> - Возвращает: <Function[]>
Возвращает копию массива слушателей события с именем eventName.
server.on('connection', (stream) => {
console.log('someone connected!');
});
console.log(util.inspect(server.listeners('connection')));
// Prints: [ [Function] ] copy
emitter.off(eventName, listener)
-
eventName<string> | <symbol> -
listener<Function> - Возвращает: <EventEmitter>
Псевдоним для emitter.removeListener().
emitter.on(eventName, listener)
-
eventName<string> | <symbol> Имя события. -
listener<Function> Функция обратного вызова - Возвращает: <EventEmitter>
Добавляет функцию listener в конец массива слушателей события с именем eventName. Проверка того, был ли listener уже добавлен, не выполняется. Несколько вызовов с одной и той же комбинацией eventName и listener приведут к тому, что listener будет добавлен и вызван несколько раз.
server.on('connection', (stream) => {
console.log('someone connected!');
}); copy Возвращает ссылку на 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
// aCommonJS
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)
-
eventName<string> | <symbol> Имя события. -
listener<Function> Функция обратного вызова - Возвращает: <EventEmitter>
Добавляет функцию listener для события с именем eventName, которая вызывается один раз. При следующем вызове eventName этот слушатель удаляется, а затем вызывается.
server.once('connection', (stream) => {
console.log('Ah, we have our first user!');
}); copy Возвращает ссылку на 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
// aCommonJS
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)
-
eventName<string> | <symbol> Имя события. -
listener<Function> Функция обратного вызова - Возвращает: <EventEmitter>
Добавляет функцию listener в начало массива слушателей события с именем eventName. Проверка того, был ли listener уже добавлен, не выполняется. Несколько вызовов с одной и той же комбинацией eventName и listener приведут к тому, что listener будет добавлен и вызван несколько раз.
server.prependListener('connection', (stream) => {
console.log('someone connected!');
}); copy Возвращает ссылку на EventEmitter, что позволяет объединять вызовы в цепочку.
emitter.prependOnceListener(eventName, listener)
-
eventName<string> | <symbol> Имя события. -
listener<Function> Функция обратного вызова - Возвращает: <EventEmitter>
Добавляет функцию listener для события с именем eventName в начало массива слушателей. При следующем вызове eventName этот слушатель удаляется, а затем вызывается.
server.prependOnceListener('connection', (stream) => {
console.log('Ah, we have our first user!');
}); copy Возвращает ссылку на EventEmitter, что позволяет объединять вызовы в цепочку.
emitter.removeAllListeners([eventName])
-
eventName<string> | <symbol> - Возвращает: <EventEmitter>
Удаляет все слушатели или слушателей указанного eventName.
Удалять слушателей, добавленных в других частях кода, не рекомендуется, особенно если экземпляр EventEmitter был создан другим компонентом или модулем (например, сокетами или файловыми потоками).
Возвращает ссылку на EventEmitter, что позволяет объединять вызовы в цепочку.
emitter.removeListener(eventName, listener)
-
eventName<string> | <symbol> -
listener<Function> - Возвращает: <EventEmitter>
Удаляет указанный listener из массива слушателей события с именем eventName.
const callback = (stream) => {
console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback); copy Метод 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:
// ACommonJS
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)
-
n<integer> - Возвращает: <EventEmitter>
По умолчанию объекты EventEmitter выводят предупреждение, если для одного события добавлено более 10 слушателей. Это полезное значение по умолчанию, помогающее обнаруживать утечки памяти. Метод emitter.setMaxListeners() позволяет изменить ограничение для данного экземпляра EventEmitter. Чтобы указать неограниченное количество слушателей, можно задать значение Infinity (или 0).
Возвращает ссылку на EventEmitter, что позволяет объединять вызовы в цепочку.
emitter.rawListeners(eventName)
-
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])
Метод 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
По умолчанию для любого отдельного события можно зарегистрировать не более 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
Этот символ следует использовать для установки обработчика, который будет только отслеживать события 'error'. Обработчики, установленные с помощью этого символа, вызываются до обычных обработчиков 'error'.
Установка обработчика с помощью этого символа не меняет поведение при возникновении события 'error'. Поэтому процесс по-прежнему аварийно завершится, если обычный обработчик 'error' не установлен.
events.getEventListeners(emitterOrTarget, eventName)
-
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)
-
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])
-
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 boomCommonJS
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!Ожидание нескольких событий, генерируемых в process.nextTick()
При использовании функции events.once() для ожидания нескольких событий, генерируемых в одной и той же группе операций process.nextTick(), или при синхронной генерации нескольких событий, следует учитывать один особый случай. В частности, поскольку очередь process.nextTick() обрабатывается до очереди микрозадач Promise и поскольку EventEmitter генерирует все события синхронно, events.once() может пропустить событие.
Модули JavaScript
import { EventEmitter, once } from 'node:events';
import process from 'node:process';
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'));CommonJS
const { EventEmitter, once } = require('node: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 до ожидания любого из них. Тогда можно использовать Promise.all(), Promise.race() или Promise.allSettled():
Модули JavaScript
import { EventEmitter, once } from 'node:events';
import process from 'node:process';
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'));CommonJS
const { EventEmitter, once } = require('node: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
- Тип: <boolean>
Изменяет значение параметра captureRejections по умолчанию для всех новых объектов EventEmitter.
events.captureRejectionSymbol
- Тип: <symbol>
Symbol.for('nodejs.rejection')
См. инструкции по написанию пользовательского обработчика отклонений.
events.listenerCount(emitter, eventName)
emitter.listenerCount().-
emitter<EventEmitter> Эмиттер, для которого выполняется запрос -
eventName<string> | <symbol> Имя события
Метод класса, возвращающий количество обработчиков, зарегистрированных для указанного eventName у указанного emitter.
Модули JavaScript
import { EventEmitter, listenerCount } from 'node:events';
const myEmitter = new EventEmitter();
myEmitter.on('event', () => {});
myEmitter.on('event', () => {});
console.log(listenerCount(myEmitter, 'event'));
// Prints: 2CommonJS
const { EventEmitter, listenerCount } = require('node:events');
const myEmitter = new EventEmitter();
myEmitter.on('event', () => {});
myEmitter.on('event', () => {});
console.log(listenerCount(myEmitter, 'event'));
// Prints: 2
events.on(emitter, eventName[, options])
-
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 hereCommonJS
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])
-
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)
-
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) {
let disposable;
try {
signal.addEventListener('abort', (e) => e.stopImmediatePropagation());
disposable = addAbortListener(signal, (e) => {
// Do something when signal is aborted.
});
} finally {
disposable?.[Symbol.dispose]();
}
}Модули JavaScript
import { addAbortListener } from 'node:events';
function example(signal) {
let disposable;
try {
signal.addEventListener('abort', (e) => e.stopImmediatePropagation());
disposable = addAbortListener(signal, (e) => {
// Do something when signal is aborted.
});
} finally {
disposable?.[Symbol.dispose]();
}
}Класс: events.EventEmitterAsyncResource extends EventEmitter
Объединяет 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> Включает автоматический перехват отклонений Promise. По умолчанию: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.
API EventTarget и Event
Объекты EventTarget и Event представляют собой специфичную для Node.js реализацию веб-API EventTarget, предоставляемую некоторыми основными API Node.js.
const target = new EventTarget();
target.addEventListener('foo', (event) => {
console.log('foo event happened!');
}); copy EventTarget Node.js и EventTarget DOM
Между EventTarget Node.js и веб-API EventTarget есть два ключевых различия:
- В то время как экземпляры DOM
EventTargetмогут образовывать иерархию, в Node.js нет понятия иерархии и распространения событий. То есть событие, отправленное объектуEventTarget, не распространяется по иерархии вложенных целевых объектов, у каждого из которых может быть собственный набор обработчиков события. - В
EventTargetNode.js, если обработчик события является асинхронной функцией или возвращаетPromise, а возвращённыйPromiseотклоняется, отклонение автоматически перехватывается и обрабатывается так же, как и исключение, синхронно выброшенное обработчиком (подробности см. в разделе обработка ошибокEventTarget).
NodeEventTarget и EventEmitter
Объект NodeEventTarget реализует изменённое подмножество API EventEmitter, которое позволяет ему в некоторых ситуациях близко эмулировать EventEmitter. NodeEventTarget не является экземпляром EventEmitter и в большинстве случаев не может использоваться вместо EventEmitter.
- В отличие от
EventEmitter, любойlistenerможно зарегистрировать не более одного раза для каждого событияtype. Попытки зарегистрироватьlistenerнесколько раз игнорируются. NodeEventTargetне эмулирует полный APIEventEmitter. В частности, APIprependListener(),prependOnceListener(),rawListeners()иerrorMonitorне эмулируются. События'newListener'и'removeListener'также не будут генерироваться.- Для событий с типом
'error'объектNodeEventTargetне реализует никакого особого поведения по умолчанию. - Объект
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 = new EventTarget();
target.addEventListener('foo', handler1);
target.addEventListener('foo', handler2);
target.addEventListener('foo', handler3);
target.addEventListener('foo', handler4, { once: true }); copy
Обработка ошибок EventTarget
По умолчанию, если зарегистрированный обработчик события выбрасывает исключение (или возвращает Promise, который отклоняется), ошибка считается неперехваченным исключением в process.nextTick(). Это означает, что неперехваченные исключения в EventTargets по умолчанию приводят к завершению процесса Node.js.
Исключение, выброшенное внутри обработчика события, не препятствует вызову остальных зарегистрированных обработчиков.
Для событий типа 'error', например EventEmitter, объект EventTarget не реализует никакой специальной обработки по умолчанию.
В настоящее время ошибки сначала передаются событию process.on('error'), а затем попадают в process.on('uncaughtException'). Это поведение объявлено устаревшим и в одном из будущих выпусков будет изменено, чтобы привести EventTarget в соответствие с другими API Node.js. Код, зависящий от события process.on('error'), следует привести в соответствие с новым поведением.
Класс: Event
Объект Event является адаптацией веб-API Event. Экземпляры создаются внутри Node.js.
event.bubbles
- Тип: <boolean> Всегда возвращает
false.
В Node.js это свойство не используется и приводится исключительно для полноты описания.
event.cancelBubble
event.stopPropagation().- Тип: <boolean>
Псевдоним для event.stopPropagation(), если установлено значение true. В Node.js это свойство не используется и приводится исключительно для полноты описания.
event.cancelable
- Тип: <boolean> Значение True, если событие было создано с параметром
cancelable.
event.composed
- Тип: <boolean> Всегда возвращает
false.
В Node.js это свойство не используется и приводится исключительно для полноты описания.
event.composedPath()
Возвращает массив, содержащий текущий EventTarget в качестве единственного элемента, либо пустой массив, если событие не отправляется. В Node.js это свойство не используется и приводится исключительно для полноты описания.
event.currentTarget
- Тип: <EventTarget>
EventTarget, отправляющий событие.
Псевдоним для event.target.
event.defaultPrevented
- Тип: <boolean>
Имеет значение true, если cancelable равно true и был вызван event.preventDefault().
event.eventPhase
- Тип: <number> Возвращает
0, если событие не отправляется, и2, если оно отправляется.
В Node.js это свойство не используется и приводится исключительно для полноты описания.
event.initEvent(type[, bubbles[, cancelable]])
Избыточен по отношению к конструкторам событий и не позволяет задать composed. В Node.js это свойство не используется и приводится исключительно для полноты описания.
event.isTrusted
- Тип: <boolean>
Событие "abort" объекта <AbortSignal> генерируется со значением isTrusted, равным true. Во всех остальных случаях значение равно false.
event.preventDefault()
Устанавливает свойство defaultPrevented в значение true, если cancelable равно true.
event.returnValue
event.defaultPrevented.- Тип: <boolean> Значение True, если событие не было отменено.
Значение event.returnValue всегда противоположно значению event.defaultPrevented. В Node.js это свойство не используется и приводится исключительно для полноты описания.
event.srcElement
event.target.- Тип: <EventTarget>
EventTarget, отправляющий событие.
Псевдоним для event.target.
event.stopImmediatePropagation()
Прекращает вызов обработчиков событий после завершения работы текущего обработчика.
event.stopPropagation()
В Node.js это свойство не используется и приводится исключительно для полноты описания.
event.target
- Тип: <EventTarget>
EventTarget, отправляющий событие.
event.timeStamp
- Тип: <number>
Метка времени в миллисекундах, соответствующая моменту создания объекта Event.
Класс: EventTarget
eventTarget.addEventListener(type, listener[, options])
-
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 }); copy
eventTarget.dispatchEvent(event)
-
event<Event> - Возвращает: <boolean>
true, если значение атрибутаcancelableсобытия равно false или его методpreventDefault()не был вызван; в противном случае —false.
Отправляет event списку обработчиков для event.type.
Зарегистрированные обработчики событий вызываются синхронно в порядке их регистрации.
eventTarget.removeEventListener(type, listener[, options])
-
type<string> -
listener<Function> | <EventListener> -
options<Object>-
capture<boolean>
-
Удаляет listener из списка обработчиков события type.
Класс: CustomEvent
- Наследует: <Event>
Объект CustomEvent является адаптацией веб-API CustomEvent. Экземпляры создаются внутри Node.js.
event.detail
- Тип: <any> Возвращает пользовательские данные, переданные при инициализации.
Только для чтения.
Класс: NodeEventTarget
- Наследует: <EventTarget>
NodeEventTarget — это специфичное для Node.js расширение EventTarget, эмулирующее подмножество API EventEmitter.
nodeEventTarget.addListener(type, listener)
-
type<string> -
listener<Function> | <EventListener> -
Возвращает: <EventTarget> this
Специфичное для Node.js расширение класса EventTarget, эмулирующее соответствующий API EventEmitter. Единственное различие между addListener() и addEventListener() заключается в том, что addListener() возвращает ссылку на EventTarget.
nodeEventTarget.emit(type, arg)
-
type<string> -
arg<any> - Возвращает: <boolean>
true, если существуют обработчики событий, зарегистрированные дляtype; в противном случае —false.
Специфичное для Node.js расширение класса EventTarget, отправляющее arg списку обработчиков для type.
nodeEventTarget.eventNames()
- Возвращает: <string[]>
Специфичное для Node.js расширение класса EventTarget, возвращающее массив названий type событий, для которых зарегистрированы обработчики.
nodeEventTarget.listenerCount(type)
Специфичное для Node.js расширение класса EventTarget, возвращающее количество обработчиков событий, зарегистрированных для type.
nodeEventTarget.setMaxListeners(n)
-
n<number>
Специфичное для Node.js расширение класса EventTarget, устанавливающее максимальное количество обработчиков событий равным n.
nodeEventTarget.getMaxListeners()
- Возвращает: <number>
Специфичное для Node.js расширение класса EventTarget, возвращающее максимальное количество обработчиков событий.
nodeEventTarget.off(type, listener[, options])
-
type<string> -
listener<Function> | <EventListener> -
options<Object>-
capture<boolean>
-
-
Возвращает: <EventTarget> this
Специфичный для Node.js псевдоним для eventTarget.removeEventListener().
nodeEventTarget.on(type, listener)
-
type<string> -
listener<Function> | <EventListener> -
Возвращает: <EventTarget> this
Специфичный для Node.js псевдоним для eventTarget.addEventListener().
nodeEventTarget.once(type, listener)
-
type<string> -
listener<Function> | <EventListener> -
Возвращает: <EventTarget> this
Специфичное для Node.js расширение класса EventTarget, добавляющее обработчик once для указанного события type. Эквивалентно вызову on с параметром once, установленным в true.
nodeEventTarget.removeAllListeners([type])
-
type<string> -
Возвращает: <EventTarget> this
Специфичное для Node.js расширение класса EventTarget. Если указан type, удаляет все зарегистрированные обработчики для type; в противном случае удаляет все зарегистрированные обработчики.
nodeEventTarget.removeListener(type, listener[, options])
-
type<string> -
listener<Function> | <EventListener> -
options<Object>-
capture<boolean>
-
-
Возвращает: <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-v22.x/docs/api/events.html