Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
EventEmitter в Node.js
EventEmitter — это фундаментальный паттерн в Node.js для асинхронной коммуникации между компонентами через события. Это класс, который позволяет объекту излучать именованные события и подписываться на них.
Что это такое
EventEmitter реализует паттерн Observer (Наблюдатель). Когда происходит какое-то событие, все подписчики на это событие получают уведомление и могут на него среагировать.
Базовая концепция:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
// Подписываемся на событие
myEmitter.on('user:created', (user) => {
console.log(`Welcome, ${user.name}!`);
});
// Излучаем событие
myEmitter.emit('user:created', { name: 'John' });
// Вывод: Welcome, John!
Основные методы
on() / addEventListener() — подписаться на событие
emitter.on('event', (data) => {
console.log('Event happened:', data);
});
// Можно добавить несколько слушателей
emitter.on('event', () => console.log('Listener 2'));
emitter.on('event', () => console.log('Listener 3'));
// Все три выполнятся
emitter.emit('event');
once() — подписаться на событие один раз
emitter.once('payment:success', () => {
console.log('Payment received!');
});
emitter.emit('payment:success'); // Логируется
emitter.emit('payment:success'); // Ничего не произойдёт
off() / removeListener() — отписаться от события
const handler = () => console.log('Event fired');
emitter.on('event', handler);
emitter.off('event', handler);
emitter.emit('event'); // Ничего не произойдёт
removeAllListeners() — удалить всех слушателей
emitter.removeAllListeners('event');
// или все события
emitter.removeAllListeners();
listenerCount() — количество слушателей
const count = emitter.listenerCount('event');
console.log(`Listeners: ${count}`);
Реальные примеры в Node.js
Пример 1: Stream (основан на EventEmitter)
const fs = require('fs');
const stream = fs.createReadStream('large-file.txt');
stream.on('data', (chunk) => {
console.log('Received chunk:', chunk.length);
});
stream.on('end', () => {
console.log('File read complete');
});
stream.on('error', (err) => {
console.error('Error:', err);
});
Пример 2: HTTP Server
const http = require('http');
const server = http.createServer();
server.on('request', (req, res) => {
res.end('Hello World');
});
server.on('clientError', (err) => {
console.error('Client error:', err);
});
server.listen(3000);
Пример 3: Custom Business Logic
const EventEmitter = require('events');
class OrderProcessor extends EventEmitter {
async processOrder(order) {
this.emit('order:started', order);
try {
const payment = await this.processPayment(order);
this.emit('payment:success', payment);
await this.sendConfirmation(order);
this.emit('order:completed', order);
} catch (err) {
this.emit('order:failed', { order, error: err });
}
}
}
const processor = new OrderProcessor();
processor.on('payment:success', () => {
console.log('Payment received, sending email...');
});
processor.on('order:completed', (order) => {
console.log('Order complete, updating inventory...');
});
processor.on('order:failed', ({ error }) => {
console.error('Failed:', error);
// логировать в систему мониторинга
});
await processor.processOrder({ id: 1, amount: 100 });
Когда использовать
Хорошо подходит для:
- Decoupling — компоненты не знают друг о друге, только о событиях
- Real-time приложения — WebSockets, игры, live notifications
- Асинхронные операции — callbacks, promise-based workflows
- Pub-Sub паттерн — когда один компонент производит события, много потребляют
Плохо подходит для:
- Синхронной логики — используй return значения
- Множественных зависимостей между событиями (спагетти код)
- Если нужна гарантия доставки (используй очереди: RabbitMQ, Kafka)
Потенциальные проблемы
Memory Leaks:
// Плохо — listener никогда не удаляется
setInterval(() => {
emitter.on('event', () => {});
}, 1000);
// Хорошо — удаляем когда больше не нужно
const handler = () => {};
emitter.on('event', handler);
// потом
emitter.off('event', handler);
Error handling:
// Слушатель выбросит ошибку, но остальные продолжат
emitter.on('event', () => {
throw new Error('Oops!');
});
emitter.on('event', () => {
console.log('Still works'); // Выполнится несмотря на ошибку выше
});
// Нужен error listener
emitter.on('error', (err) => {
console.error('Handled:', err);
});
EventEmitter в современных практиках
В большинстве случаев вместо обычного EventEmitter используют:
- Promises/Async-Await — для однократных операций
- RxJS/Observable — для потоков данных
- Message brokers (RabbitMQ, Kafka) — для распределённых систем
Но EventEmitter остаётся мощным инструментом для локальной асинхронной коммуникации и входит в ядро Node.js.