Введение в событийно-ориентированное программирование в Node.js

1
компьютеры и технологии 28.webp.webp

Последнее обновление 13.10.2023 — Василий Иванов

Ключевые выводы

  • Программирование, управляемое событиями, — хороший выбор для интерактивных приложений, особенно приложений с графическим пользовательским интерфейсом, поскольку оно позволяет коду реагировать на действия пользователя в любом порядке.
  • Программирование, управляемое событиями, обычно используется в веб-приложениях, где прослушиватели событий срабатывают, когда пользователи взаимодействуют с DOM.
  • Реализовывать событийно-ориентированное программирование в Node.js легко с помощью класса EventEmitter, который позволяет создавать собственные события и подключать прослушиватели событий для их обработки.

При создании любого программного приложения одним из важнейших решений является выбор подходящей парадигмы для вашего кода.

Программирование, управляемое событиями, — хороший выбор для интерактивных приложений, которые реагируют на действия пользователя, которые могут происходить в любом порядке. Эта парадигма более популярна в приложениях с графическим пользовательским интерфейсом, чем в программах командной строки или коде встроенных систем.

По теме:  «Ростех» хочет создать свой процессор

Что такое события?

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

Примером базового события является нажатие кнопки для выполнения определенного действия. При нажатии кнопки генерируется событие, а функция, которая запускается при нажатии, называется прослушивателем (или обработчиком) событий.

Что такое событийно-ориентированное программирование?

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

Эта парадигма в основном используется при создании пользовательских интерфейсов и приложений реального времени, где такое событие, как действие пользователя, должно запускать действие в системе.

Эта парадигма очень популярна при создании веб-приложений, где прослушиватели событий срабатывают, когда пользователи взаимодействуют с объектной моделью документа (DOM).

На следующем изображении показано, как работает поток в программировании, управляемом событиями. Когда происходит событие, канал событий получает его и передает соответствующему прослушивателю для обработки:

Программирование, управляемое событиями, в Node.js

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

Благодаря программированию, управляемому событиями, Node.js позволяет создавать серверные приложения, которые могут обрабатывать взаимодействие с пользователем, операции ввода-вывода и обработку данных в реальном времени. Это происходит неблокирующим образом, что приводит к повышению производительности и более плавной работе пользователя.

Реализация событийно-ориентированного программирования в Node.js проста, если вы понимаете основы определения, запуска и обработки событий.

Класс EventEmitter

С помощью класса EventEmitter в Node.js вы можете создавать собственные события и подключать прослушиватели событий для их обработки. Чтобы использовать класс в своем коде, импортируйте его из модуля событий следующим образом:

 // CommonJS
const { EventEmitter } = require("events")

// ES6
import { EventEmitter } from "events"

После этого класс и его функции-члены будут доступны для использования в вашем приложении. Чтобы начать генерировать и обрабатывать события, инициализируйте новый экземпляр класса EventEmitter.

Например:

 const FoodEvents = new EventEmitter()

При этом создается новый объект-эмиттер под названием FoodEvents, который может генерировать события и регистрировать прослушиватели. Класс EventEmmitter предоставляет три метода для прослушивания события: on, addListener и Once.

Метод on — это самая базовая функция для добавления прослушивателей событий, и addListener работает точно так же. Они оба принимают имя события и функцию обратного вызова в качестве аргументов. Обратный вызов — это фактическая функция-обработчик. Вы можете использовать on и addListener взаимозаменяемо.

Вот как вы обрабатываете событие, используя метод on:

 FoodEvents.on("cookie_ready", (data) => {
    console.log("Cookie ready for packaging, data received: ", data);
})

Использование addListener в качестве прямой альтернативы on:

 FoodEvents.addListener("cookie_ready", (data) => {
    console.log(
        "Cookie will now be packaged and sent out, data received: ",
        data
    );
})

Оба этих примера добавят обратный вызов в массив прослушивателей событий cookie_ready. Если вы используете оба, их обратные вызовы будут выполняться по порядку.

Метод Once регистрирует однократный прослушиватель событий, который запускается при следующем возникновении события. После этого система удалит его из массива слушателей.

Вот как использовать Once для обработки одноразового события:

 FoodEvents.once("cookie_sent", (data) => {
    console.log("Cookie is sent out, data received: ", data);
})

В этом случае отправитель будет прослушивать событие cookie_sent только один раз и удалять обработчик после его запуска.

Все три метода возвращают эмиттер, поэтому вы можете связать вызовы с любым из них.

Не забывайте, что для того, чтобы прослушиватель мог обработать событие, приложение должно в какой-то момент выдать это событие. Вот пример кода для создания события cookie_ready с использованием метода submit:

 function bakeCookie() {
    console.log("Cookie is baking, almost ready...")

    setTimeout(() => {
        FoodEvents.emit("cookie_ready", { flavor: "vanilla cookie" })
    }, 3000)
}

bakeCookie()

Когда вы запустите этот код, который выводит в консоль уведомление о том, что файл cookie запекается, ждет 3 секунды и генерирует событие cookie_ready, вы получите вывод, подобный изображению ниже:

Это демонстрирует, как прослушиватели событий запускаются в том порядке, в котором вы их регистрируете.

Класс EventEmitter предоставляет больше методов, в том числе:

  • RemoveListener: удаляет экземпляр прослушивателя из массива прослушивателей событий. Для этой цели также доступен метод off.
  • prependListener: этот метод также регистрирует прослушиватель, но вместо добавления его в конец массива прослушивателей он добавляет его в начало. Затем он запустится раньше всех других прослушивателей, которые вы, возможно, уже зарегистрировали.
  • prependOnceListener: работает так же, как prependListener, но прослушиватель запускается только один раз, как и в случае с Once.
  • RemoveAllListeners: эта функция удаляет всех зарегистрированных прослушивателей для определенного именованного события или всех прослушивателей, если вы не передаете ей аргумент.
  • прослушиватели: возвращает массив прослушивателей имени события, которое вы передаете ему в качестве аргумента.
  • eventNames: вы можете использовать эту функцию, чтобы получить все имена событий, для которых вы уже зарегистрировали прослушиватель.
  • setMaxListeners: Node.js по умолчанию выдает предупреждение, когда вы регистрируете более 10 прослушивателей для события, чтобы предотвратить утечки памяти. Вы можете настроить это значение по умолчанию, используя setMaxListeners. Вы также можете проверить это значение с помощью getMaxListeners.

Пакет событий предоставляет комплексные функциональные возможности для событийно-ориентированного программирования в Node.js.

Каковы лучшие практики событийно-ориентированного программирования?

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

  • Используйте краткие и описательные имена для событий, чтобы обеспечить чистоту и удобство обслуживания базы кода.
  • Примените хорошие методы обработки и ведения журнала ошибок, чтобы облегчить их отладку.
  • Избегайте ада обратных вызовов (вложения нескольких обратных вызовов) при написании прослушивателей событий. Вместо этого используйте обещания JavaScript.
  • Не создавайте слишком много слушателей для одного события. Вместо этого рассмотрите возможность разделения событий и объединения их в цепочку.

Создавайте приложения с правильной архитектурой

Общее правило, применимое к созданию программного обеспечения, заключается в принятии соответствующих решений по архитектуре и проектированию. Если вы примените неправильный подход к созданию приложения, вы рано или поздно столкнетесь с последствиями.

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