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

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

В этой статье я покажу, как реализовать простую шину событий в Javascript.

Шина событий, основанная на этом примере, также доступна в виде облегченной библиотеки для браузера и Node.js. Библиотека и ее документация находится по этому адресу.



Что такое автобус для мероприятий

Шина событий реализует шаблон издатель / подписчик. Его можно использовать для разделения компонентов приложения, чтобы компонент мог реагировать на события, инициированные другим компонентом, без прямой зависимости между ними. Им нужно только знать шину событий.

Каждый подписчик может подписаться на конкретное событие. Подписчик будет уведомлен, когда событие, на которое он подписан, будет опубликовано в шине событий.

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

Реализация шины событий

В этой реализации подписчик - это простая функция. Функция вызывается, когда интересующее событие публикуется в шине событий.

Чтобы сопоставить событие подписчикам, можно использовать простой объект. Формат данных в этом объекте будет: {eventType: {id: callback}}. Например:

{
  event1: { 1: func1, 2: func2 },
  event2: { 3: func3 }
}

События event1 и event2 могут быть любого типа. В большинстве случаев имеет смысл использовать простые строки.
Подписчики func1, func2 и func3 - это простые функции Javascript.
func1 и func2 - подписчики, подписанные на события типа event1.
func3 - это подписчик, подписанный на события типа event2.

Идентификаторы 1, 2 и 3 будут использоваться позже для отказа от подписки подписчиков.

Подписывайся

Функция subscribe принимает в качестве аргументов интересующее событие и подписчика.

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

В этом примере я использую генератор идентификаторов для получения уникальных идентификаторов.
Идентификаторы используются для немедленной идентификации (за время O (1)) подписчика при вызове функции отказаться от подписки.

Я представил полную реализацию очень простого генератора идентификаторов в конце этой статьи.

Вместо использования генератора идентификаторов в реальной реализации можно было бы рассмотреть возможность использования символов ES6.

const subscriptions = { }
const getNextUniqueId = getIdGenerator()
function subscribe(eventType, callback) {
  const id = getNextUniqueId()
  // create new entry for eventType
  if(!subscriptions[eventType])
    subscriptions[eventType] = { }
  // the callback is registered
  subscriptions[eventType][id] = callback
  return {
    unsubscribe: () => {
      delete subscriptions[eventType][id]
      if(Object.keys(subscriptions[eventType]).length === 0)
        delete subscriptions[eventType]
    }
  }
}

Публиковать

Функция публикации принимает в качестве аргументов событие и аргументы для подписчиков.

Если для eventType нет подписчиков, он просто возвращается.

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

function publish(eventType, arg) {
  if(!subscriptions[eventType])
    return
  Object.keys(subscriptions[eventType])
        .forEach(id => subscriptions[eventType][id](arg))
}

использование

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

Мы можем подписаться на слушателя вот так:

const subscription = EventBus.subscribe(
  "print",
  message => console.log(`printing: ${message}`)
)

Затем мы можем создать событие, подобное этому:

EventBus.publish("print", "some text")

Если в какой-то момент мы не заинтересованы в реакции на события типа «печать», мы можем отказаться от подписки следующим образом:

subscription.unsubscribe()

Полная реализация

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

Код этого поста также доступен в this Gist и был использован в качестве основы для этой готовой к использованию библиотеки.

Где ты меня найдешь?

Следуйте за мной в Twitter: https://twitter.com/psoffritti
Мой сайт / портфолио: pierfrancescosoffritti.com
Моя учетная запись GitHub: https://github.com/PierfrancescoSoffritti < br /> Моя учетная запись LinkedIn: linkedin.com/in/pierfrancescosoffritti/en