Введение

Вообще, если бы мой блог был логичным, то эта статья вышла бы раньше предыдущей статьи о реактивном программировании, потому что штуки эти очень похожи. Я бы даже сказал, что реактивное программирование — это частный случай событийно-ориентированной архитектуры.

Вообще, в JavaScript очень удобно работать с событиями. В Node.js API есть даже целый класс EventEmitter, который только этим и занимается. Да и в целом, само по себе Node.js API построено вокруг своеобразной асинхронной событийно-ориентированной архитектуры.

Так что ж это за архитектура такая?

Событийно-ориентированная архитектура

Событийно-ориентированная архитектура (многим гораздо привычнее видеть ее английское название, event-driven architecture), как понятно из названия, завязана на события. Создание событий и реагирование на них — это, в общем-то, вся ее суть.

Событие — это некое изменение состояния (это уже сильно ближе к реактивному программированию, но все же). Давайте определим, какой путь проходит это самое событие.

Генерация события

Для начала событие должно случиться (ну, или появиться, кому как удобнее). Языком из Википедии скажем, что некий генератор событий регистрирует какой-то факт и создает событие. В JavaScript этим занимается EventEmitter, точнее, его метод emit(). Выглядит это примерно так:

const eventEmitter = new EventEmitter();

eventEmitter.emit('eventName', ...args);

Обработка события

Что такое eventName, достаточно понятно — это имя ивента, его идентификатор. Но метод emit() принимает еще и неограниченное количество аргументов, которые он передаст обработчикам этого ивента. Обработчики ивента создаются методом on(). Смотрите:

const eventEmitter = new EventEmitter();

eventEmitter.on('eventName', () => {
    console.log('вот что произойдет, когда ивент eventName случится');
});

eventEmitter.on('eventName', (arg1, arg2) => {
    console.log('да, обработчиков у одного ивента может быть несколько, они выполнятся в порядке их объявления');
    console.log(`этот обработчик принимает еще и два аргумента, arg1 и arg2`);
    console.log(`${arg1}, ${arg2}`); // 1, 2
});

eventEmitter.on('eventName', function (...args) {
    console.log(`a этот обработчик принимает любое количество аргументов`);
    const joinedArgs = args.join(', ');
    console.log(`${joinedArgs}`); // 1, 2, 3, 4, 5
});

eventEmitter.emit('eventName', 1, 2, 3, 4, 5); // создаем событие eventName

Еще у EventEmitter есть методы eventNames() (вернет массив с именами ивентов), listenerCount(eventName) (отдаст количество обработчиков eventName) и куча других, менее полезных. За ними — в документацию.

Там же можно почитать о наследнике EventEmitterEventEmitterAsyncResource, который то же самое, только с методами AsyncResource.

Итоги

Статья вышла коротенькой — но что поделать, если про события в JS, как ни странно, много не расскажешь — ничего сложного там нет. Но эту статью можно рассматривать как подготовку к статье о WebSocket — это такой способ двустороннего обмена событиями сервера с клиентом.

Будет интересно. Stay tuned!