Что такое паттерн наблюдатель (обсервер)
Что проверяют
Понимаете ли вы механику подписки, потому что на ней стоит весь фронтенд: события DOM, сторы, реактивность фреймворков, поток сообщений из сокета. Второй слой вопроса это дисциплина: помните ли вы про отписку и умеете ли объяснить, чем наблюдатель отличается от шины событий.
Как отвечать
Субъект хранит список подписчиков и уведомляет их при изменении состояния. Связь один ко многим: подписчики не знают друг о друге, субъект не знает их типов и работает с ними через общий контракт.
function createStore(initial) {
let state = initial;
const subs = new Set();
return {
get: () => state,
set(next) {
state = next;
[...subs].forEach((fn) => fn(state));
},
subscribe(fn) {
subs.add(fn);
return () => subs.delete(fn);
},
};
}Главная деталь тут в том, что subscribe возвращает функцию отписки: без неё паттерн превращается в источник утечек.
Полезно показать, что в браузере паттерн уже везде: addEventListener, а также наблюдатели за пересечением, размером и мутациями DOM. В React подписку на внешний источник делают через useSyncExternalStore, иначе при конкурентном рендере состояние на экране разъедется с состоянием источника.
И разведите понятия: у наблюдателя субъект знает своих подписчиков напрямую, а шина событий добавляет посредника с темами, где отправитель и получатель друг о друге не знают вовсе.
Где спотыкаются
Не отписываются. Колбэк держит замыкание на размонтированный компонент, обновления уходят в никуда, память растёт, а в консоли появляются попытки обновить то, чего уже нет. В компонентах отписку возвращают из эффекта.
Меняют список подписчиков прямо во время рассылки: кто-то внутри своего колбэка отписывается или добавляет нового. Обход исходной коллекции при этом пропускает элементы, поэтому рассылать нужно по копии списка.
Не думают про ошибки: исключение в одном подписчике обрывает рассылку остальным, и часть интерфейса тихо остаётся на старых данных. Вызов подписчика стоит защищать, а ошибку отправлять в мониторинг.