Паттерн Observer — «JavaScript Design Patterns, 2017» Эдди Османи. Перевод: часть 6.2

Оригинальный текст — https://addyosmani.com/

Не забудьте про первую часть.


Реализации Publish/Subscribe

Publish/Subscribe очень хорошо вписывается в экосистему JavaScript, в основном потому, что ECMAScript управляется событиями. Это особенно хорошо видно в браузере, поскольку DOM использует в работе события в качестве основного API взаимодействия.

Тем не менее, ни ECMAScript, ни DOM не предоставляют объекты и методы для создания пользовательских систем событий в коде (за исключением, возможно, DOM3 CustomEvent, который связан с DOM).

К счастью, популярные библиотеки JavaScript, такие как dojo, jQuery и YUI, уже имеют утилиты, которые могут помочь в простой реализации паттерна Publish/Subscribe c минимальными усилиями. Ниже мы можем увидеть некоторые примеры этого:

Для тех, кто хочет использовать паттерн Publish/Subscribe на ванильном JavaScript (или в другой библиотеке), есть ряд чистых реализаций:

  • AmplifyJS включает в себя чистую реализацию, которая может быть использована с любой библиотекой;
  • Radio.js;
  • PubSubJS;
  • Pure JS PubSub от Peter Higgins.

Разработчики jQuery имеют множество других реализаций паттерна, начиная от плагина jQuery от Peter’а Higgins’а и заканчивая оптимизированным Pub/Sub jQuery от Ben’а Alman’а. Ссылки можно найти ниже:

Чтобы мы могли оценить ванильные реализации шаблона, давайте рассмотрим минималистичную версию Publish/Subscribe, созданной в проекте pubsubz. Пример демонстрирует основные концепции подписки, публикации, а также отмены подписки.

Теперь мы можем использовать публикации и подписки на интересующие события следующим образом:

Пример: уведомление подписчика

Давайте представим, что у нас есть веб-приложение, которое выводит какую-либо информацию в реальном времени.

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

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

В нашей реализации подписчик слушает топик «newDataAvailable», чтобы узнать, доступна ли новая информация. Как только в топике появится уведомление, оно приведет к тому, что gridUpdate добавит новую строку в нашу таблицу, содержащую всю информацию. Он также обновит дату последних изменений.

Пример: разбивка приложения реализацией Pub/Sub  от Ben Alman

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

Мы добавляем новые данные в существующие массивы, а затем используем их в наших шаблонах с методом .template () из библиотеки Underscore.

HTML

Javascript

Пример: разбиение приложения на jQuery с Ajax

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

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

Связь различных частей приложения и их зависимость между собой на высоком уровне усложняют переиспользование кода. Это означает, что наличие какой-либо логики в обратных вызовах будет не очень хорошей реализацией, если мы захотим сделать дальнейшие Ajax-вызовы (или какое-либо другое поведение). Нам придется писать часть кода несколько раз. Поэтому мы можем начать использовать pub/sub уже в самом начале разработки и сэкономить немного времени.

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

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

HTML

Javascipt

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