--- Редагувати 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 в компонент InputPresentational, що означає, що ніде не потрібно підписки. Детальніше про цей підхід читайте тут
--- Редагувати 3 - "Офіційне" рішення (2017/04/09)
Я говорив з Уордом Беллом про це запитання в NGConf (я навіть показав йому цю відповідь, яку він сказав, що вона правильна), але він сказав мені, що команда документів для Angular мала рішення щодо цього питання, яке не публікується (хоча вони працюють над тим, щоб його затвердити ). Він також сказав мені, що я можу оновити свою відповідь "SO" за допомогою майбутньої офіційної рекомендації.
Ми повинні використовувати все рішення вперед - додати private ngUnsubscribe = new Subject();поле до всіх компонентів, які мають .subscribe()дзвінки до Observables у коді свого класу.
Потім ми закликаємо 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.
Subscriptionshttp-requestsможна ігнорувати, оскільки вони дзвонять лишеonNextодин раз і потім дзвонятьonComplete.RouterЗамість викликівonNextкілька разів і ніколи не може назватиonComplete(не впевнений , що ...). Те саме стосується іObservablesEvents. Тому я думаю, що це має бутиunsubscribed.