Lab / JS / JavaScript

Обзёрвер (наблюдатель) как патерн JavaScript

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

Экземпляр (объект) содержит коллекцию объектов (наблюдателей) и уведомляет их обо всех случаях, когда происходят какие либо изменения их состояния. Звучит немного сложно не так ли? Я тоже так подумал впервые столкнувнись с данным паттерном. Давайте рассмотрим небольшой пример, что бы понять как тут всё устроенно?

Представьте сиуацию когда вам необходимо одновременно обновлять несколько элементов по наступлению определённого события, например при печати в поле input. Представим что нам нужно создать кнопку "подписатся", что бы начать получать изменения, как только вы что либо будете печатать в поле. Так же будет не лишним создать кнопку "отписаться" это может оказаться полезным, если вам больше не нужно передавать изменения состояния в конкретный объект. Давайте напишем код для этого примера:

// Объявление класса
class Observable {
 // каждый экземпляр класса Observer
 // начинается с пустого массива элементов (наблюдателей)
 // которые реагируют на изменение состояния
 constructor() {
 this.observers = [];
 }

 // Добавление возможность подписаться на новый объект / элемент DOM
 // по сути добавление чего-либо к массиву наблюдателей
 subscribe(f) {
 this.observers.push(f);
 }

 // Добавление возможности отписаться от наблюдения за объектом
 unsubscribe(f) {
 this.observers = this.observers.filter(subscriber => subscriber !== f);
 }

 // Обновление всех подписанных объекты / DOM элементов 
 // и передача соответствующих данных каждому из них
 notify(data) {
 this.observers.forEach(observer => observer(data));
 }
}

Пример кейса:

// связь с DOM элементами
const input = document.querySelector('.js-input');
const p1 = document.querySelector('.js-p1');
const p2 = document.querySelector('.js-p2');
const p3 = document.querySelector('.js-p3');

// Действия для добавления в массив наблюдателей
const updateP1 = text => p1.textContent = text;
const updateP2 = text => p2.textContent = text;
const updateP3 = text => p3.textContent = text;

// Создание нового класса Observer
const headingsObserver = new Observable();

// Подписка наблюдателей
headingsObserver.subscribe(updateP1);
headingsObserver.subscribe(updateP2);
headingsObserver.subscribe(updateP3);

// Уведомить наблюдателей о новых данных по событию
input.addEventListener('keyup', e => {
 headingsObserver.notify(e.target.value);
});

See the Pen ZJjxKW by Mark (@mbogrov) on CodePen.

Эта очень упрощенная версия шаблона наблюдателя может избавить вас от загрузки некоторых увесистых фреймворков, таких как Vue или React или Angular. Если вы хотите ещё больше подобных примеров, очень рекомендую приобрести книгу Шаблоны в JavaScrip за авторством всеми любимого Эдди Асмани.