Джедайские приемы на JavaScript: магические свойства транслятора событий

О чем мы?

Event Emitter можно перевести как «транслятор» или «эмиттер» событий. Звучит как название штуки, умеющей генерировать событие, которое может «услышать» кто угодно.

Представьте себе такую схему: в вашем асинхронном коде определенный участок может «крикнуть» остальным, что он выполнил свою задачу, а другие части «услышат» этот сигнал и примут соответствующие меры.

Event Emitter — это шаблон, который можно реализовать разными способами. Основная идея в том, чтобы грамотно создать основу для управления событиями и реализовать возможность любым элементам «подписаться» на него (и быть в курсе происходящего). С другими шаблонами проектирования вы можете познакомиться в нашей статье.

Уже интересно, как такая магия может работать? Итак, мы хотим добиться кода, который затем можно будет использовать так:

Начнем.

Реализация

Как видите, конструктор нашего класса будет инициализировать поле events, пока что делая его пустым объектом. Задача этого поля — хранить события, «подписавшиеся» на нас (то есть в нем будут храниться функции).

Метод subscribe:

Этот метод принимает в качестве аргументов название события (например, event:name-changed, как в нашем примере) и функцию, которая будет вызываться, когда будет инициироваться транслируемое событие.

Одна из ключевых особенностей функций в JavaScript состоит в том, что функции — это этакие «объекты первого класса», то есть мы можем передать функцию в качестве параметра другой функции, как в методе subscribe().

Метод emit:

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

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

Давайте решим эту проблему. Пусть метод subscribe() возвращает функцию unsubscribe(), которую позже можно будет использовать, чтобы отписаться от события.

Как мы помним, в JavaScript особенные функции — их легко можно вернуть из другой функции. Теперь метод subscribe() можно использовать следующим образом:

Вызывая сохраненную в переменной функцию unsubscribe(), мы отписываемся от события.

Вот и все. Пока-пока, утечки памяти!

Вот тут можно попробовать весь получившийся код в действии.

Источник: Medium