Вместо этого используйте 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
мы должны:
- Ждите обратного звонка.
- Сохраните результат обратного вызова в переменной.
- Привяжите к этой переменной в шаблоне. ТЗ (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 )