Вместо этого используйте AsyncPipe

Один из лучших практических принципов Angular - всегда использовать AsyncPipe, когда это возможно, и использовать .subscribe() только тогда, когда побочный эффект является абсолютной необходимостью и его нельзя избежать.

Что такое наблюдаемое?

Observable - это абстракция асинхронного потока данных. Например, когда мы смотрим на anObservable, он представляет собой поток строк, которые будут доставляться одна за другой с течением времени. TK (https://medium.com/isop-nepal/subscribe-vs-async-pipe-in-angular-21bb38f3ee49)

Но когда Observable изменяется, как мы отображаем данные? Здесь мы используем .subscribe().

Функция подписки

Мы передаем Observable, комбинируя его и сохраняя в разные переменные с разными комбинациями операторов, но, в конце концов, Observable<T> сам по себе бесполезен. Нам нужен способ завершить Observable и извлечь из него тип T. Вот для чего используется .subscribe: чтобы подписаться на результирующий поток и завершить наблюдаемое. TK (https://kimsereyblog.blogspot.com/2018/05/async-pipe-versus-subscribe-in-angular.html)

Мы все признаем эту закономерность, когда я избавляюсь от подписки с помощью метода unsubscribe():

С помощью этого шаблона я могу быть уверен, что моя подписка всегда будет прекращена, и я в безопасности от утечки памяти! Обратите внимание, что нам абсолютно необходимо создать подписку во время инициализации (ngOnInit) компонента, а позже, когда он будет уничтожен, нам нужно проверить, активна ли еще подписка, отменить ее и удалить все ссылки на нее. TK (https://medium.com/angular-in-depth/why-you-have-to-unsubscribe-from-observable-92502d5639d0)

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

Например, см. Код ниже:

Итак, вот как я могу полностью отказаться от подписки.

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

Предположим, у меня есть serviceFunctionReturningObservable() функция, которая возвращает мне наблюдаемое со следующей подписью. И в родительском component.ts файле я хочу подписаться на этот Observable и передать эти подписанные данные Children для использования.

serviceFunctionReturningObservable( flag: Flag ):
Observable<boolean> {}

Субоптимальная версия моего кода (без использования асинхронного канала) с обычным .subscribe ()

Затем в соответствующем файле шаблона .html я получаю доступ к данным следующим образом:

[isSomeBooleanVarToPassDownToChildComp]="isSomeBooleanVarToPassDownToChildComp"

Теперь, чтобы понять, что происходит выше, мы должны отметить, что обычно для рендеринга результата Promise или Observable мы должны:

  1. Ждите обратного звонка.
  2. Сохраните результат обратного вызова в переменной.
  3. Привяжите к этой переменной в шаблоне. ТЗ (https://codecraft.tv/courses/angular/pipes/async-pipe/)

Итак, следуя этому потоку, мы делаем следующее:

  • Создание логического Observable, которое публикует логическое значение в ngOnInit().
  • Отображение значения isSomeBooleanVarToPassDownToChildComp в нашем шаблоне.
  • Подписка на вывод этой Observable цепочки и сохранение логического значения в свойстве isSomeBooleanVarToPassDownToChildComp.

AsyncPipe

Но с AsyncPipe мы можем использовать Promises и Observables непосредственно в нашем шаблоне, не сохраняя результат в промежуточном свойстве или переменной. ТЗ (https://codecraft.tv/courses/angular/pipes/async-pipe/)

AsyncPipe принимает в качестве аргумента Observable или Promise, вызывает subscribe или присоединяет обработчик then, затем ожидает асинхронного результата, прежде чем передать его вызывающей стороне. ТЗ (https://codecraft.tv/courses/angular/pipes/async-pipe/)

Так что в этом случае мы можем сделать еще лучше и никогда не использовать subscribe, используя AsyncPipe.

«Разворачивает значение из асинхронного примитива.

Асинхронный канал подписывается на Observable или Promise и возвращает последнее значение, которое он испустил. Когда выдается новое значение, асинхронный конвейер отмечает компонент, который нужно проверить на наличие изменений. Когда компонент уничтожается, асинхронный конвейер автоматически отменяет подписку, чтобы избежать потенциальных утечек памяти ». - Документация по Angular

Зачем использовать AsyncPipe?

  • Потому что он автоматически подписывается и отменяет подписку на Observables по мере создания или уничтожения компонента, что является отличной функцией.
  • Это особенно важно в случае долгоживущих Observables (например, определенных Observables, возвращаемых маршрутизатором или AngularFire).
  • Кроме того, потому что это делает наши программы более легкими для чтения и более декларативными с меньшим количеством переменных состояния в наших классах компонентов.

Используя AsyncPipe, нам не нужно выполнять subscribe и хранить какие-либо промежуточные данные в нашем компоненте, например:

В случае, если мне нужно было передать что-то с начальными данными подписки, мне пришлось бы сделать это:

Мы перенаправляем наш Observable прямо на AsyncPipe, он выполняет для нас подписку, а затем возвращает все, что ему было передано. ТЗ (https://codecraft.tv/courses/angular/pipes/async-pipe/)

Используя AsyncPipe, мы:

  • Не нужно вызывать subscribe на нашем Observable и сохранять промежуточные данные в нашем компоненте.
  • Не нужно забывать отказываться от подписки на Observable, когда компонент уничтожен.
  • Меньше переменных состояния. ТЗ (https://codecraft.tv/courses/angular/pipes/async-pipe/)

Другой пример принципа

В приведенном ниже случае arrayListFromSelector$ исходит из селектора (с использованием пакета reselect и потреблением состояния redux-reducer).

Первоначально я подписывался на этот селектор от reselect/redux с .subscribe() следующим образом.

Начальный рабочий код с .subscribe ()

А затем передать эти подписанные данные arrayListFromSelector компоненту Child, где я, в свою очередь, просто передам эти данные, так как в конечном итоге они будут использованы ng-select для передачи в раскрывающийся список.

Однако вашему Child компоненту не нужно ничего знать о Observable.

Окончательный отредактированный код без использования .subscribe ()

И теперь arrayListFromSelector доступен в Child, как локальная переменная состояния.

Как правило, шаблон «подписаться и в функции подписки скопировать данные в состояние компонента» не является здоровым. Это заставляет вас излишне вовлекаться в обнаружение изменений.

Исключения

Но в некоторых случаях вам следует явно подписаться на Observables в компонентах и ​​директивах.

Например, когда Observable меняет внешний мир. Чаще всего это делается путем передачи POST (или DELETE или PUT) через HTTP внутреннему API.

При работе с HttpClient мы можем столкнуться с ситуацией, когда просто не сможем использовать AsyncPipe для Observable. Чтобы погрузиться глубже, давайте рассмотрим несколько примеров:

  • Повторная отправка запросов при изменении параметров.
  • Получение данных параллельно из нескольких потоков.
  • Отправка индивидуальных запросов.
  • Создание, удаление и обновление данных.

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

Во всех этих случаях компонент - это объект, который «хочет» и «потребляет» Observable для фактического выполнения, поэтому он также должен подписываться.

Но в противном случае, когда это возможно:

Мы всегда должны использовать AsyncPipe, когда это возможно, и использовать .subscribe только тогда, когда побочный эффект является абсолютной необходимостью, поскольку мы в безопасности, пока остаемся в Observable. Код, завершающий Observable, должен быть фреймворком (Angular) и последним элементом (UI) . TK ( https://kimsereyblog.blogspot.com/2018/05/async-pipe-versus-subscribe -in-angular.html )