← Назад к вопросам

Что такое EventEmitter?

2.0 Middle🔥 251 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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 });

Когда использовать

Хорошо подходит для:

  1. Decoupling — компоненты не знают друг о друге, только о событиях
  2. Real-time приложения — WebSockets, игры, live notifications
  3. Асинхронные операции — callbacks, promise-based workflows
  4. Pub-Sub паттерн — когда один компонент производит события, много потребляют

Плохо подходит для:

  1. Синхронной логики — используй return значения
  2. Множественных зависимостей между событиями (спагетти код)
  3. Если нужна гарантия доставки (используй очереди: 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.