Впервые я наткнулся на функцию defer около года назад, когда занялся почти готовым приложением Angular. На самом деле оказалось, что в этом нет необходимости. С тех пор я не видел никакого разумного применения этой функции до тех пор, пока Кшиштоф Тшесневски не выступил с докладом на местном собрании Angular. Потом я просветлел и нашел по крайней мере одно достойное упоминания применение функции defer.

Короткое напоминание JS

Прежде чем мы перейдем к функции defer, давайте кратко рассмотрим правила области видимости JavaScript.

Приведенный ниже код не будет работать, так как в вашей среде IDE вы увидите красное подчеркивание:

переменная с областью видимости блока "bar" используется перед ее объявлением

Однако следующий код прекрасен:

Следовательно, вы можете ссылаться на переменную bar в выражении, если выражение выполняется после инициализации переменной.

Образец наблюдателя

Допустим, вы хотите иметь службу уведомлений, которая просто следует шаблону Observer, а именно: вы можете отправить новое уведомление, и все подписанные объекты получат сообщение. Кусок пирога с использованием RxJS.

Хотя он очень похож на пример из официальных документов Angular, есть одна вещь, на которую я всегда жалуюсь, а именно на неправильный порядок полей классов. В общем, за общедоступными полями должны следовать защищенные и частные. Это урок, который я извлек из мира Java.

Итак, давайте попробуем переместить общедоступное поле notifications $ перед частными полями.

К сожалению, появляется следующее сообщение об ошибке:

свойство используется до его инициализации

Как это исправить?

Придите на помощь

Надеюсь, вы заметили, что проблема, с которой мы столкнулись, очень похожа на проблему из абзаца Краткое напоминание JS.

Согласно официальной документации RxJS, функция defer:

Создает Observable, который при подписке вызывает фабрику Observable, чтобы создать Observable для каждого нового Observer.

И это именно то, что нам нужно! Нам нужно отложить создание наблюдаемого объекта notifications $, чтобы notificationsSubject уже был инициализирован.

Давайте посмотрим на реализацию сервиса:

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