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

Для чего используется Event Emitter в Node.JS?

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

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

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

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

Event Emitter в Node.js

EventEmitter — это паттерн в Node.js, который позволяет объектам генерировать события и другим объектам слушать эти события. Это основа асинхронного программирования в Node.js.

Базовая идея

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

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

// Слушаем событие 'message'
emitter.on('message', (data) => {
  console.log('Получили сообщение:', data);
});

// Генерируем событие
emitter.emit('message', 'Hello, World!');
// Вывод: "Получили сообщение: Hello, World!"

Основные методы

1. on() — слушать событие

const { EventEmitter } = require('events');
const emitter = new EventEmitter();

// Каждый раз когда event происходит
emitter.on('data', (value) => {
  console.log('Данные:', value);
});

emitter.emit('data', 42);   // "Данные: 42"
emitter.emit('data', 100);  // "Данные: 100"

2. once() — слушать один раз

emitter.once('startup', () => {
  console.log('Система запустилась');
});

emitter.emit('startup'); // "Система запустилась"
emitter.emit('startup'); // Не выведет (слушаем только один раз)

3. emit() — генерировать событие

emitter.emit('error', new Error('Что-то пошло не так'));
emitter.emit('user-login', { userId: 123, timestamp: Date.now() });

4. off() / removeListener() — прекратить слушать

const handler = (data) => console.log(data);

emitter.on('message', handler);
emitter.emit('message', 'test');  // Выведет

emitter.off('message', handler);  // Удаляем слушатель
emitter.emit('message', 'test');  // Не выведет

5. removeAllListeners() — удалить всех слушателей

emitter.removeAllListeners('message');
// или
emitter.removeAllListeners(); // удалить всех

Практические примеры

1. Читание файла

const { EventEmitter } = require('events');
const fs = require('fs');

class FileReader extends EventEmitter {
  read(filename) {
    fs.readFile(filename, (err, data) => {
      if (err) {
        this.emit('error', err);
      } else {
        this.emit('data', data);
      }
    });
  }
}

const reader = new FileReader();

reader.on('data', (data) => {
  console.log('Файл прочитан:', data.toString());
});

reader.on('error', (err) => {
  console.error('Ошибка:', err.message);
});

reader.read('file.txt');

2. HTTP сервер (встроенный EventEmitter)

const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200);
  res.end('OK');
});

// HTTP сервер это EventEmitter!
server.on('request', (req, res) => {
  console.log(`Запрос: ${req.method} ${req.url}`);
});

server.on('error', (err) => {
  console.error('Ошибка сервера:', err);
});

server.on('connection', (socket) => {
  console.log('Новое соединение');
});

server.listen(3000);

3. Pubsub паттерн (издатель-подписчик)

class EventBus extends EventEmitter {}

const eventBus = new EventBus();

// Сервис 1: Заказы
class OrderService {
  createOrder(order) {
    console.log('Заказ создан:', order);
    eventBus.emit('order.created', order);
  }
}

// Сервис 2: Уведомления
class NotificationService {
  constructor() {
    eventBus.on('order.created', (order) => {
      console.log('Отправляем уведомление о заказе:', order.id);
    });
  }
}

// Сервис 3: Аналитика
class AnalyticsService {
  constructor() {
    eventBus.on('order.created', (order) => {
      console.log('Логируем заказ в аналитику');
    });
  }
}

const orders = new OrderService();
const notifications = new NotificationService();
const analytics = new AnalyticsService();

orders.createOrder({ id: 1, total: 100 });
// Вывод:
// "Заказ создан: { id: 1, total: 100 }"
// "Отправляем уведомление о заказе: 1"
// "Логируем заказ в аналитику"

Встроенные в Node.js EventEmitter'ы

1. Stream (потоки)

const fs = require('fs');

const stream = fs.createReadStream('large-file.txt');

stream.on('data', (chunk) => {
  console.log(`Прочитано ${chunk.length} байт`);
});

stream.on('end', () => {
  console.log('Файл полностью прочитан');
});

stream.on('error', (err) => {
  console.error('Ошибка чтения:', err);
});

2. HTTP request/response

const http = require('http');

const req = http.get('http://api.example.com/data', (res) => {
  res.on('data', (chunk) => {
    console.log('Получены данные:', chunk.toString());
  });
  
  res.on('end', () => {
    console.log('Ответ закончился');
  });
});

req.on('error', (err) => {
  console.error('Ошибка запроса:', err);
});

3. Child Process

const { spawn } = require('child_process');

const child = spawn('ls', ['-la']);

child.stdout.on('data', (data) => {
  console.log('Output:', data.toString());
});

child.on('close', (code) => {
  console.log('Процесс закончился с кодом:', code);
});

TypeScript + EventEmitter

import { EventEmitter } from 'events';

interface OrderCreatedEvent {
  id: number;
  total: number;
  userId: number;
}

class OrderService extends EventEmitter {
  createOrder(data: OrderCreatedEvent) {
    console.log('Заказ создан');
    this.emit('order.created', data);
  }
}

const service = new OrderService();

service.on('order.created', (event: OrderCreatedEvent) => {
  console.log(`Заказ ${event.id} создан`);
});

service.createOrder({ id: 1, total: 100, userId: 123 });

Лучшие практики

1. Всегда слушайте 'error' событие

emitter.on('error', (err) => {
  console.error('Ошибка произошла:', err);
});

2. Удаляйте слушателей чтобы избежать утечек памяти

const handler = () => { };
emitter.on('event', handler);
// ...
emitter.off('event', handler); // Не забыть!

3. Используйте типизацию (TypeScript)

type EventMap = {
  'user.login': (userId: number) => void;
  'user.logout': (userId: number) => void;
  'error': (err: Error) => void;
};

Зачем нужен EventEmitter

  1. Decoupling — сервисы не зависят друг от друга
  2. Асинхронность — работа без блокировки
  3. Масштабируемость — легко добавить новых слушателей
  4. Читаемость — понятно что происходит
  5. Тестируемость — легко мокировать события

EventEmitter — это паттерн, который пронизывает весь Node.js. От streams до HTTP до вашей собственной бизнес-логики.

Для чего используется Event Emitter в Node.JS? | PrepBro