Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

События и EventEmitter

Событие — сообщение «что-то произошло», на которое могут откликнуться другие части программы. В браузере вы подписывались на клики через addEventListener. В Node.js ту же роль играет класс EventEmitter из модуля node:events. На нём построены сервер, потоки и многие другие встроенные объекты.

Подписка и отправка

Метод on() подписывает функцию на событие, emit() отправляет событие и передаёт данные всем подписчикам:

import { EventEmitter } from 'node:events';
 
const blog = new EventEmitter();
 
blog.on('post', (title) => {
  console.log(`Новая статья: ${title}`);
});
 
blog.emit('post', 'Привет, Node.js');
blog.emit('post', 'Работа с файлами');

Выведутся две строки «Новая статья: ...». Имя события — любая строка, которую вы придумаете.

Несколько подписчиков

На одно событие можно подписать сколько угодно функций — они вызываются по порядку подписки. Так разные части программы реагируют на одно и то же, ничего не зная друг о друге:

import { EventEmitter } from 'node:events';
 
const blog = new EventEmitter();
 
blog.on('comment', (comment) => console.log(`Записываем в журнал: ${comment.author}`));
blog.on('comment', (comment) => console.log(`Письмо автору статьи ${comment.postId}`));
 
blog.emit('comment', { postId: 1, author: 'Олег', text: 'Спасибо!' });

Свой класс с событиями

Обычно от EventEmitter наследуют свой класс. Создайте файл src/blog-events.js:

// src/blog-events.js
import { EventEmitter } from 'node:events';
 
export class Blog extends EventEmitter {
  #posts = [];
 
  addPost(title) {
    const post = { id: this.#posts.length + 1, title };
    this.#posts.push(post);
    this.emit('post:created', post);
    return post;
  }
}

Используйте его в app.js:

// app.js
import { Blog } from './src/blog-events.js';
 
const blog = new Blog();
blog.on('post:created', (post) => console.log(`Опубликовано: №${post.id} ${post.title}`));
 
blog.addPost('Привет, Node.js');

node app.js выведет «Опубликовано: №1 Привет, Node.js». Класс Blog не знает, кто его слушает, — он только сообщает о событии.

Одноразовые обработчики и отписка

МетодЧто делает
on(name, fn)Подписывает функцию
once(name, fn)Подписывает на одно срабатывание
off(name, fn)Отписывает функцию
emit(name, ...data)Отправляет событие
listenerCount(name)Число подписчиков
import { EventEmitter } from 'node:events';
 
const server = new EventEmitter();
server.once('ready', () => console.log('Сервер готов'));
 
server.emit('ready');
server.emit('ready');
console.log(server.listenerCount('ready')); // 0

«Сервер готов» выведется один раз: после первого срабатывания обработчик удаляется сам.

Частая ошибка

Событие error особенное. Если его отправить, а подписчика нет, EventEmitter бросит ошибку и программа упадёт. Поэтому у объектов, которые могут сообщать об ошибках, всегда подписывайтесь на error:

import { EventEmitter } from 'node:events';
 
const blog = new EventEmitter();
blog.on('error', (error) => console.log(`Ошибка: ${error.message}`));
 
blog.emit('error', new Error('не удалось сохранить статью'));

Без строки с blog.on('error', ...) этот код завершился бы с необработанной ошибкой.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.