--- Редактировать 4 - Дополнительные ресурсы (2018/09/01)
В недавнем эпизоде приключений в Angular Бен Леш и Уорд Белл обсуждают вопросы о том, как и когда отписаться в компоненте. Обсуждение начинается примерно в 1:05:30.
Уорд упоминает right now there's an awful takeUntil dance that takes a lot of machineryи Ша Резник упоминаетAngular handles some of the subscriptions like http and routing .
В ответ Бен упоминает, что сейчас идут обсуждения, позволяющие Observables подключаться к событиям жизненного цикла компонента Angular, а Ward предлагает Observable событий жизненного цикла, на которые компонент может подписаться, чтобы узнать, когда завершать Observables, поддерживаемые как внутреннее состояние компонента.
Тем не менее, сейчас нам в основном нужны решения, так что вот некоторые другие ресурсы.
Рекомендация по takeUntil()шаблону от члена основной команды RxJ Николаса Джеймисона и правило tslint, чтобы помочь обеспечить его соблюдение. https://ncjamieson.com/avoiding-takeuntil-leaks/
Облегченный пакет npm, который предоставляет оператор Observable, который принимает экземпляр компонента (this ) в качестве параметра и автоматически отписывается во время ngOnDestroy.
https://github.com/NetanelBasal/ngx-take-until-destroy
Еще один вариант вышеупомянутого с немного лучшей эргономикой, если вы не делаете сборки AOT (но мы все должны делать AOT сейчас).
https://github.com/smnbbrv/ngx-rx-collector
Таможенная директива *ngSubscribe которая работает как асинхронный канал, но создает встроенный вид в вашем шаблоне, чтобы вы могли ссылаться на значение «развернутый» во всем шаблоне.
https://netbasal.com/diy-subscription-handling-directive-in-angular-c8f6e762697f
В комментарии к блогу Николаса я упоминаю, что чрезмерное использование takeUntil()может быть признаком того, что ваш компонент пытается сделать слишком много, и что следует учитывать разделение существующих компонентов на компоненты Feature и Presentational . Вы можете тогда| async заметить Observable из компонента Feature в компонент InputPresentational, что означает, что подписки нигде не нужны. Подробнее об этом подходе читайте здесь
--- Редактировать 3 - «Официальное» решение (2017/04/09)
Я говорил с Уордом Беллом об этом вопросе в NGConf (я даже показал ему этот ответ, который, по его словам, был правильным), но он сказал мне, что команда разработчиков документации для Angular нашла решение этого вопроса, которое не было опубликовано (хотя они работают над его утверждением). ). Он также сказал мне, что я могу обновить свой SO-ответ следующей официальной рекомендацией.
Решение, которое мы все должны использовать в будущем, заключается в добавлении private ngUnsubscribe = new Subject();поля ко всем компонентам, к которым .subscribe()обращаютсяObservable s в своем коде класса.
Затем мы позвоним this.ngUnsubscribe.next(); this.ngUnsubscribe.complete();в нашngOnDestroy() методы.
Секретный соус (как уже отмечалось @metamaker ) - звонить takeUntil(this.ngUnsubscribe)перед каждым из наших.subscribe() вызовов, что гарантирует очистку всех подписок при уничтожении компонента.
Пример:
import { Component, OnDestroy, OnInit } from '@angular/core';
// RxJs 6.x+ import paths
import { filter, startWith, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { BookService } from '../books.service';
@Component({
selector: 'app-books',
templateUrl: './books.component.html'
})
export class BooksComponent implements OnDestroy, OnInit {
private ngUnsubscribe = new Subject();
constructor(private booksService: BookService) { }
ngOnInit() {
this.booksService.getBooks()
.pipe(
startWith([]),
filter(books => books.length > 0),
takeUntil(this.ngUnsubscribe)
)
.subscribe(books => console.log(books));
this.booksService.getArchivedBooks()
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(archivedBooks => console.log(archivedBooks));
}
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
}
Примечание: важно добавитьtakeUntil оператор как последний, чтобы предотвратить утечки с промежуточными наблюдаемыми в цепочке операторов.
--- Изменить 2 (2016/12/28)
Источник 5
В учебнике Angular глава Routing теперь заявляет следующее: «Маршрутизатор управляет наблюдаемыми объектами, которые он предоставляет, и локализует подписки. Подписки очищаются при уничтожении компонента, защищая от утечек памяти, поэтому нам не нужно отписываться от параметры маршрута наблюдаемые. " - Марк Райкок
Вот обсуждение вопросов Github для Angular docs, касающихся Router Observables, где Уорд Белл упоминает, что прояснение всего этого находится в работе.
--- Редактировать 1
Источник 4
В этом видео от NgEurope Роб Вормальд также говорит, что вам не нужно отписываться от Router Observables. Он также упоминает httpслужбу и ActivatedRoute.paramsв этом видео с ноября 2016 года .
--- Оригинальный ответ
TLDR:
Для этого вопроса существует (2) вида Observables- конечное значение и бесконечное значение.
http Observablesпроизводят конечные (1) ценности и что - то вроде DOM event listener Observablesпроизводят бесконечные значения.
Если вы вручную звоните subscribe(не используя асинхронный канал), то unsubscribeиз бесконечного Observables .
Не беспокойтесь о конечных , RxJsпозаботятся о них.
Источник 1
Я разыскал ответ Роба Вормальда в Angular's Gitter здесь .
Он заявляет (я реорганизован для ясности и акцента мое)
если это однозначная последовательность (например, HTTP-запрос), ручная очистка не нужна (при условии, что вы подписываетесь в контроллере вручную)
я должен сказать «если это последовательность, которая завершается » (из которых однозначные последовательности, а-ля http, являются одной)
если это бесконечная последовательность , вы должны отписаться, что асинхронный канал делает для вас
Также он упоминает в этом видео на YouTube об Observables, которые they clean up after themselves... в контексте Observables, которые complete(например, Promises, которые всегда выполняются, потому что они всегда производят 1 значение и заканчиваются - мы никогда не беспокоились о том, чтобы отписаться от Promises, чтобы убедиться, что они очищают xhrсобытие слушатели, верно?).
Источник 2
Также в путеводителе по Rangle Angular 2 написано
В большинстве случаев нам не нужно явно вызывать метод отказа от подписки, если мы не хотим отменить досрочно, или если наш Observable имеет более длительный срок службы, чем наша подписка. Поведение операторов Observable по умолчанию заключается в удалении подписки сразу после публикации сообщений .complete () или .error (). Имейте в виду, что RxJS был разработан для того, чтобы использовать его в режиме «забей и забудь» большую часть времени.
Когда делает фразу our Observable has a longer lifespan than our subscription ?
Он применяется, когда подписка создается внутри компонента, который уничтожается до (или незадолго до) Observableзавершения.
Я читаю это как значение, если мы подписываемся на httpзапрос или наблюдаемое, которое испускает 10 значений, и наш компонент уничтожается до того, как этот httpзапрос вернется или 10 значений будут отправлены, мы все еще в порядке!
Когда запрос вернется или, наконец, Observableбудет получено 10-е значение, все будет завершено, и все ресурсы будут очищены.
Источник 3
Если мы посмотрим на этот пример из того же руководства по Rangle, то увидим, что для Subscriptionto route.paramsтребуется значение, unsubscribe()потому что мы не знаем, когда они paramsперестанут меняться (испуская новые значения).
Компонент может быть уничтожен путем перемещения в этом случае, и в этом случае параметры маршрута, вероятно, все еще будут изменяться (они могут технически измениться до конца приложения), а ресурсы, выделенные в подписке, будут по-прежнему выделяться, поскольку не было completion.
Subscriptionчтоhttp-requestsможно игнорировать, так как они звонят толькоonNextодин раз, а затем они звонятonComplete.RouterВместо вызововonNextнесколько раз и никогда не может назватьonComplete(не уверен , что ...). То же самое касаетсяObservables отEvents. Так что, думаю, так и должно бытьunsubscribed.