--- Редагувати 4 - Додаткові ресурси (2018/09/01)
В нещодавньому епізоді Пригоди в кутовому Бен Леш та Уорд Белл обговорюють проблеми навколо того, як / коли відписатися на підписку на компонент. Обговорення розпочинається близько 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
.
У відповідь Бен згадує, що зараз ведуться дискусії, щоб дозволити спостерігачам підключитися до подій життєвого циклу компонентів углових компонентів, а Уорд пропонує «Спостережувані події життєвого циклу», на які компонент міг би підписатись як спосіб знати, коли потрібно виконати Спостереження, що підтримуються як внутрішній стан компонента.
Зважаючи на це, нам зараз потрібні рішення, тому ось деякі інші ресурси.
Рекомендація щодо takeUntil()
шаблону від основної команди команди RxJs Ніколаса Джеймісона та правило tslint, яке допоможе виконувати його. https://ncjamieson.com/avoiding-takeuntil-leaks/
Легкий пакет npm, який відкриває оператор "Спостереження", який приймає екземпляр компонента ( 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 і презентаційні компоненти повинні бути розглянуті. Потім ви можете | async
спостерігати з компонента Feature в компонент Input
Presentational, що означає, що ніде не потрібно підписки. Детальніше про цей підхід читайте тут
--- Редагувати 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 (28.12.2016)
Джерело 5
У кутовому посібнику, в главі маршрутизації, зараз зазначено наступне: "Маршрутизатор управляє спостереженнями, які він надає, і локалізує підписки. Підписки очищаються при знищенні компонента, захищаючи від витоків пам'яті, тому нам не потрібно скасовувати підписку на маршрут парами Спостерігається ". - Марк Райкок
Ось дискусія щодо питань Github для кутових документів щодо маршрутизаційних спостережень, де Уорд Белл згадує, що роз'яснення щодо всього цього є у творах.
--- Редагувати 1
Джерело 4
У цьому відео від NgEurope Роб Вормалд також говорить, що вам не потрібно скасовувати підписку на Router Observables. Він також згадує про http
службу і ActivatedRoute.params
в цьому відео з листопада 2016 року .
--- Оригінальна відповідь
TLDR:
Для цього питання існує (2) види Observables
- кінцеве значення і нескінченне значення.
http
Observables
виробляють кінцеві (1) значення і щось на зразок DOM event listener
Observables
виробляють нескінченні значення.
Якщо ви вручну викликати subscribe
(не використовуючи асинхронну трубку), то unsubscribe
з нескінченного Observables
.
Не турбуйтеся про кінцеві , RxJs
вони подбають про них.
Джерело 1
Я розшукав відповідь від Rob Wormald в GITTER кутового в тут .
Він констатує (я реорганізований для ясності, і акцент - мій)
якщо його однозначна послідовність (наприклад, запит http), ручне очищення не є необхідним (якщо припустити, що ви підписалися на контролер вручну)
я повинен сказати, "якщо її послідовність, яка завершує " (з яких послідовності з одним значенням, a la http, є одна)
якщо це нескінченна послідовність , вам слід скасувати підписку, що робить труба асинхронізації для вас
Крім того, він згадує у цьому відео на YouTube " Оглядомі", що they clean up after themselves
... в контексті "Спостережуваних", які complete
(як Обіцянки, які завжди завершуються, оскільки вони завжди створюють 1 цінність і закінчуються) - ми ніколи не турбувалися про скасування підписки на Обіцяння, щоб переконатися, що вони очистять xhr
подію слухачів, правда?).
Джерело 2
Також у посібнику з Rangle до кута 2 він читається
У більшості випадків нам не потрібно буде чітко закликати метод скасування підписки, якщо ми не хочемо скасувати достроково або наш Спостережуваний довший термін служби, ніж наша підписка. Поведінка операторів, які спостерігаються за замовчуванням, - розпоряджатися підпискою, як тільки публікуються повідомлення .complete () або .error (). Майте на увазі, що RxJS був розроблений таким чином, щоб він використовувався "вогонь і забудь" більшу частину часу.
Коли словосполучення our Observable has a longer lifespan than our subscription
застосовується?
Він застосовується, коли підписка створена всередині компонента, який знищується до Observable
завершення (або не задовго до цього) .
Я читаю це як сенс, якщо ми підписуємося на http
запит чи спостережуване, що випускає 10 значень, і наш компонент знищується до того, як цей http
запит повернеться або 10 значень не буде випущено, ми все одно в порядку!
Коли запит повернеться або 10-е значення нарешті випромінюється Observable
, завершиться і всі ресурси будуть очищені.
Джерело 3
Якщо ми подивимось на цей приклад з того ж посібника з Rangle, то можемо побачити, що Subscription
до route.params
цього потрібно, unsubscribe()
оскільки ми не знаємо, коли params
вони перестануть змінюватися (випромінюючи нові значення).
Компонент може бути знищений за допомогою навігації, і в цьому випадку парами маршруту, ймовірно, все ж змінюватимуться (технічно вони можуть змінюватися, поки додаток не закінчиться), а ресурси, виділені в підписці, все одно будуть виділятися, оскільки цього не було completion
.
Subscription
shttp-requests
можна ігнорувати, оскільки вони дзвонять лишеonNext
один раз і потім дзвонятьonComplete
.Router
Замість викликівonNext
кілька разів і ніколи не може назватиonComplete
(не впевнений , що ...). Те саме стосується іObservable
sEvent
s. Тому я думаю, що це має бутиunsubscribed
.