Angular / RxJs Quando devo cancelar a assinatura do `Subscription`

Quando devo armazenar as instâncias da Subscription e invocar unsubscribe() durante o ciclo de vida do NgOnDestroy e quando posso simplesmente ignorá-las?

Salvar todas as inscrições introduz muita confusão no código do componente.

Guia do Cliente HTTP ignora assinaturas como esta:

 getHeroes() { this.heroService.getHeroes() .subscribe( heroes => this.heroes = heroes, error => this.errorMessage = error); } 

No mesmo tempo Route & Navigation Guide diz que:

Eventualmente, vamos navegar em outro lugar. O roteador removerá esse componente do DOM e o destruirá. Precisamos limpar depois de nós mesmos antes que isso aconteça. Especificamente, devemos cancelar a inscrição antes que o Angular destrua o componente. Não fazer isso pode criar um memory leaks.

Nós cancelamos a assinatura do nosso Observable no método ngOnDestroy .

 private sub: any; ngOnInit() { this.sub = this.route.params.subscribe(params => { let id = +params['id']; // (+) converts string 'id' to a number this.service.getHero(id).then(hero => this.hero = hero); }); } ngOnDestroy() { this.sub.unsubscribe(); } 

— Edit 3 – A Solução ‘Oficial’ (2017/04/09)

Falei com Ward Bell sobre essa questão na NGConf (até mostrei a ele a resposta que ele disse estar correta), mas ele me disse que a equipe de documentação da Angular tinha uma solução para essa questão que não foi publicada (embora esteja trabalhando para aprová-la ). Ele também me disse que eu poderia atualizar minha resposta de SO com a próxima recomendação oficial.

A solução que todos nós devemos usar daqui para frente é adicionar um private ngUnsubscribe: Subject = new Subject(); campo para todos os componentes que possuem chamadas .subscribe() para Observable s dentro de seu código de class.

Em seguida, chamamos this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); em nossos methods ngOnDestroy() .

O molho secreto (como notado por @metamaker ) é chamar .takeUntil(this.ngUnsubscribe) antes de cada uma de nossas chamadas .takeUntil(this.ngUnsubscribe) .subscribe() , que garantirão que todas as assinaturas serão limpas quando o componente for destruído.

Exemplo:

 import { Component, OnDestroy, OnInit } from '@angular/core'; import 'rxjs/add/operator/takeUntil'; // import { takeUntil } from 'rxjs/operators'; // for rxjs ^5.5.0 lettable operators import { Subject } from 'rxjs/Subject'; import { MyThingService } from '../my-thing.service'; @Component({ selector: 'my-thing', templateUrl: './my-thing.component.html' }) export class MyThingComponent implements OnDestroy, OnInit { private ngUnsubscribe: Subject = new Subject(); constructor( private myThingService: MyThingService, ) { } ngOnInit() { this.myThingService.getThings() .takeUntil(this.ngUnsubscribe) .subscribe(things => console.log(things)); /* if using lettable operators in rxjs ^5.5.0 this.myThingService.getThings() .pipe(takeUntil(this.ngUnsubscribe)) .subscribe(things => console.log(things)); */ this.myThingService.getOtherThings() .takeUntil(this.ngUnsubscribe) .subscribe(things => console.log(things)); } ngOnDestroy() { this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); } } 

Nota: É importante include o operador takeUntil como o último para evitar vazamentos com observáveis ​​intermediários na cadeia do operador.

— Edição 2 (2016/12/28)

Fonte 5

O tutorial Angular, o capítulo Roteamento agora afirma o seguinte: “O Roteador gerencia os observáveis ​​que ele fornece e localiza as assinaturas. As assinaturas são limpas quando o componente é destruído, protegendo contra vazamentos de memory, portanto, não precisamos cancelar a assinatura de a rota params Observável “. – Mark Rajcok

Aqui está uma discussão sobre os problemas do Github para os documentos angulares sobre os Observables do roteador, onde Ward Bell menciona que os esclarecimentos para tudo isso estão em andamento.

— Editar 1

Fonte 4

Neste vídeo da NgEurope, Rob Wormald também diz que você não precisa cancelar a assinatura do Router Observables. Ele também menciona o serviço http e o ActivatedRoute.params neste vídeo de novembro de 2016 .

— Resposta Original

TLDR:

Para esta questão existem (2) tipos de Observables – valor finito e valor infinito .

http Observables produz valores finitos (1) e algo parecido com um event listener DOM Observables produzem valores infinitos .

Se você chamar manualmente a subscribe (não usando o pipe asynchronous), unsubscribe de Observables infinitos .

Não se preocupe com os finitos , os RxJs cuidarão deles.

Fonte 1

Eu localizei uma resposta de Rob Wormald no Angitter’s Gitter aqui .

Ele afirma (eu reorganizei para clareza e ênfase é minha)

se for uma sequência de valor único (como uma solicitação http), a limpeza manual é desnecessária (supondo que você se inscreva no controlador manualmente)

Eu deveria dizer “se é uma sequência que completa ” (das quais sequências de valor único, a la http, são uma)

se for uma sequência infinita , você deve cancelar a assinatura que o canal asynchronous faz por você

Ele também menciona neste vídeo do youtube sobre Observables que they clean up after themselves … no contexto de Observables que complete (como Promises, que sempre completam porque eles estão sempre produzindo 1 valor e terminando – nós nunca nos preocupamos em cancelar inscrição de Promises para Certifique-se de que eles limpam os ouvintes de events xhr , certo?).

Fonte 2

Também no guia Rangle para Angular 2 ele lê

Na maioria dos casos, não precisaremos chamar explicitamente o método de cancelamento de assinatura, a menos que desejemos cancelá-lo antecipadamente ou que nosso Observável tenha uma vida útil mais longa do que a nossa assinatura. O comportamento padrão dos operadores Observable é descartar a assinatura assim que as mensagens .complete () ou .error () forem publicadas. Tenha em mente que o RxJS foi projetado para ser usado em uma forma de “ignorar e esquecer” a maior parte do tempo.

Quando a frase que o our Observable has a longer lifespan than our subscription aplica?

Aplica-se quando uma assinatura é criada dentro de um componente que é destruído antes (ou não ‘longo’ antes) do Observable concluído.

Eu li isso como significando que se assinarmos uma solicitação http ou um observável que emite 10 valores e nosso componente for destruído antes que a solicitação http retorne ou os 10 valores tenham sido emitidos, ainda estamos ok!

Quando a solicitação retornar ou o 10º valor for finalmente emitido, o Observable será concluído e todos os resources serão limpos.

Fonte 3

Se olharmos para este exemplo a partir do mesmo guia Rangle, podemos ver que a Subscription para route.params requer um unsubscribe() porque não sabemos quando esses params irão parar de mudar (emitindo novos valores).

O componente pode ser destruído navegando, caso em que os parâmetros da rota provavelmente ainda estarão mudando (eles podem tecnicamente mudar até que o aplicativo termine) e os resources alocados na assinatura ainda seriam alocados porque não houve uma completion .

Você não precisa ter muitas assinaturas e cancelar a assinatura manualmente. Use o conjunto RxJS.Subject e takeUntil para manipular assinaturas como um chefe:

 import {Subject} from "rxjs/Subject"; @Component( { moduleId: __moduleName, selector: 'my-view', templateUrl: '../views/view-route.view.html', } ) export class ViewRouteComponent implements OnDestroy { componentDestroyed$: Subject = new Subject(); constructor(protected titleService: TitleService) { this.titleService.emitter1$ .takeUntil(this.componentDestroyed$) .subscribe( (data: any) => { // ... do something 1 } ); this.titleService.emitter2$ .takeUntil(this.componentDestroyed$) .subscribe( (data: any) => { // ... do something 2 } ); // ... this.titleService.emitterN$ .takeUntil(this.componentDestroyed$) .subscribe( (data: any) => { // ... do something N } ); } ngOnDestroy() { this.componentDestroyed$.next(true); this.componentDestroyed$.complete(); } } 

A abordagem alternativa , que foi proposta por @acumartini nos comentários , usa takeWhile em vez de takeUntil . Você pode preferir, mas lembre-se que desta maneira sua execução Observável não será cancelada no ngDestroy de seu componente (por exemplo, quando você faz cálculos demorados ou espera por dados do servidor). O método, que é baseado em takeUntil , não tem essa desvantagem e leva ao cancelamento imediato da solicitação. Agradecemos a @AlexChe pela explicação detalhada nos comentários .

Então aqui está o código:

 @Component( { moduleId: __moduleName, selector: 'my-view', templateUrl: '../views/view-route.view.html', } ) export class ViewRouteComponent implements OnDestroy { alive: boolean = true; constructor(protected titleService: TitleService) { this.titleService.emitter1$ .takeWhile(() => this.alive) .subscribe( (data: any) => { // ... do something 1 } ); this.titleService.emitter2$ .takeWhile(() => this.alive) .subscribe( (data: any) => { // ... do something 2 } ); // ... this.titleService.emitterN$ .takeWhile(() => this.alive) .subscribe( (data: any) => { // ... do something N } ); } // Probably, this.alive = false MAY not be required here, because // if this.alive === undefined, takeWhile will stop. I // will check it as soon, as I have time. ngOnDestroy() { this.alive = false; } } 

A class Subscription possui um recurso interessante:

Representa um recurso descartável, como a execução de um Observable. Uma Assinatura tem um método importante, cancelar assinatura, que não aceita argumentos e apenas descarta o recurso mantido pela assinatura.
Além disso, as assinaturas podem ser agrupadas através do método add (), que appendá uma Assinatura filha à Assinatura atual. Quando uma assinatura for cancelada, todos os filhos (e seus netos) também serão cancelados.

Você pode criar um object de Assinatura agregado que agrupe todas as suas assinaturas. Você faz isso criando uma Assinatura vazia e adicionando assinaturas a ela usando seu método add() . Quando seu componente é destruído, você só precisa cancelar a assinatura da assinatura agregada.

 @Component({ ... }) export class SmartComponent implements OnInit, OnDestroy { private subscriptions = new Subscription(); constructor(private heroService: HeroService) { } ngOnInit() { this.subscriptions.add(this.heroService.getHeroes().subscribe(heroes => this.heroes = heroes)); this.subscriptions.add(/* another subscription */); this.subscriptions.add(/* and another subscription */); this.subscriptions.add(/* and so on */); } ngOnDestroy() { this.subscriptions.unsubscribe(); } } 

Depende. Se, ao chamar someObservable.subscribe() , você iniciar algum recurso que deve ser liberado manualmente quando o ciclo de vida de seu componente terminar, você deverá chamar theSubscription.unsubscribe() para evitar memory leaks.

Vamos dar uma olhada em seus exemplos:

getHero() retorna o resultado de http.get() . Se você olhar para o código-fonte angular 2, http.get() cria dois ouvintes de evento:

 _xhr.addEventListener('load', onLoad); _xhr.addEventListener('error', onError); 

e chamando unsubscribe() , você pode cancelar o pedido, bem como os ouvintes:

 _xhr.removeEventListener('load', onLoad); _xhr.removeEventListener('error', onError); _xhr.abort(); 

Note que _xhr é específico da plataforma, mas eu acho que é seguro assumir que é um XMLHttpRequest() no seu caso.

Normalmente, isso é evidência suficiente para garantir uma chamada manual de unsubscribe() . Mas, de acordo com essa especificação do WHATWG , o XMLHttpRequest() está sujeito à garbage collection depois de “concluído”, mesmo se houver ouvintes de evento conectados a ele. Então eu acho que é por isso que o guia oficial angular 2 omite unsubscribe() e deixa o CG limpar os ouvintes.

Quanto ao seu segundo exemplo, depende da implementação dos params . A partir de hoje, o guia oficial angular não mostra mais a inscrição de params . Eu olhei para src novamente e descobri que params é apenas um BehaviorSubject . Como nenhum ouvinte de evento ou timers foi usado, e nenhuma variável global foi criada, deve ser seguro omitir unsubscribe() .

O ponto principal da sua pergunta é que sempre chame unsubscribe() como uma proteção contra memory leaks, a menos que você tenha certeza de que a execução do observável não cria variables ​​globais, adicione ouvintes de events, defina timeres ou faça qualquer outra coisa que resulte em vazamentos de memory.

Em caso de dúvida, analise a implementação desse observável. Se o observável tiver escrito alguma lógica de limpeza em seu unsubscribe() , que normalmente é a function que é retornada pelo construtor, então você tem uma boa razão para considerar seriamente chamar unsubscribe() .

Algumas das melhores práticas em relação a descadastrações observáveis ​​dentro de componentes Angulares:

Uma citação de Routing & Navigation

Ao se inscrever em um observável em um componente, você quase sempre organiza a desinscrição quando o componente é destruído.

Existem alguns observáveis ​​excepcionais onde isso não é necessário. Os observáveis ​​da ActivatedRoute estão entre as exceções.

O ActivatedRoute e seus observáveis ​​são isolados do próprio roteador. O roteador destrói um componente roteado quando não é mais necessário e o RotateActivated injetado morre com ele.

Sinta-se à vontade para cancelar a inscrição de qualquer maneira. É inofensivo e nunca é uma má prática.

E ao responder aos seguintes links:

  • (1) Devo cancelar a assinatura do Angular 2 Http Observables?
  • (2) É necessário cancelar a assinatura de observáveis ​​criados pelos methods Http?
  • (3) RxJS: Não cancelar a inscrição
  • (4) A maneira mais fácil de cancelar a assinatura de Observables em Angular
  • (5) Documentação para RxJS Unsubscribing
  • (6) A desinscrição em um serviço é meio que inútil, pois não há chance de vazamentos de memory
  • (7) Precisamos cancelar a assinatura do observável que conclui / com erros?
  • (8) Um comentário sobre o http observável

Coletei algumas das melhores práticas em relação a descuidas observáveis ​​dentro de componentes Angulares para compartilhar com você:

  • http anulação de assinatura observável do http é condicional e devemos considerar os efeitos do ‘retorno de chamada de assinatura’ sendo executado após o componente ser destruído caso a caso. Sabemos que o angular desinscreve e limpa o próprio http observável (1) , (2) . Embora isso seja verdade da perspectiva dos resources, ele conta apenas metade da história. Digamos que estamos falando de chamar diretamente http de dentro de um componente, e a resposta http demorou mais do que o necessário para que o usuário fechasse o componente. O manipulador subscribe() ainda será chamado mesmo que o componente seja fechado e destruído. Isso pode ter efeitos colaterais indesejados e, nos piores cenários, deixar o estado do aplicativo quebrado. Também pode causar exceções se o código no retorno de chamada tentar chamar algo que acabou de ser descartado. Contudo ao mesmo tempo ocasionalmente desejam-se. Digamos que você esteja criando um cliente de e-mail e acione um som quando o e-mail terminar de enviar – bem, você ainda quer que isso ocorra mesmo se o componente estiver fechado ( 8 ).
  • Não há necessidade de cancelar a assinatura de observáveis ​​que concluíram ou com erro. No entanto, não há mal em fazê-lo (7) .
  • Use o AsyncPipe tanto quanto possível porque ele automaticamente cancela a assinatura do observável na destruição de componentes.
  • route.params subscrição dos observáveis ActivatedRoute como route.params se eles estiverem inscritos dentro de um nested (Adicionado dentro de tpl com o seletor de componente) ou componente dynamic, pois eles podem ser inscritos muitas vezes desde que o componente pai / host exista. Não é necessário cancelar a inscrição deles em outros cenários, conforme mencionado na citação acima, em Documentos de Routing & Navigation .
  • Anular subscrição de observáveis ​​globais partilhados entre componentes que são expostos através de um serviço Angular, por exemplo, uma vez que podem ser subscritos várias vezes desde que o componente seja inicializado.
  • Não é necessário cancelar a assinatura dos observáveis ​​internos do serviço, pois um serviço Angular nunca é destruído, a menos que todo o seu aplicativo seja destruído, não há motivo real para cancelar a assinatura dele e não há possibilidade de vazamentos de memory. (6)
  • Use uma técnica abstrata para evitar qualquer confusão de código que possa resultar de descadastrações. Você pode gerenciar suas assinaturas com takeUntil (3) ou você pode usar este pacote npm mencionado em (4) A maneira mais fácil de cancelar a assinatura do Observables em Angular .
  • Sempre cancele a assinatura dos observáveis ​​do FormGroup como form.valueChanges e form.statusChanges
  • Sempre cancelar a inscrição de observables do serviço Renderer2 como renderer2.listen
  • Cancele a inscrição de todos os outros observáveis ​​como uma etapa de guarda de memory leaks até que o Angular Docs nos informe explicitamente quais observáveis ​​são desnecessários para serem cancelados (Verifique o problema: (5) Documentação para Desinscrição de RxJS (Abrir) ).
  • Bônus: Sempre use as maneiras angulares de vincular events como o HostListener pois o angular se preocupa em remover os ouvintes de events, se necessário, e evita qualquer memory leaks em potencial devido a ligações de events.

Uma boa dica final : Se você não sabe se um observável está sendo automaticamente cancelado / finalizado ou não, adicione um callback complete para se subscribe(...) e verifique se ele é chamado quando o componente é destruído.

Angular 2 documentação oficial fornece uma explicação para quando cancelar a inscrição e quando pode ser ignorado com segurança. Dê uma olhada neste link:

https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

Procure o parágrafo com o header Pai e as crianças se comuniquem por meio de um serviço e, em seguida, a checkbox azul:

Observe que capturamos a assinatura e cancelamos a inscrição quando o AstronautComponent é destruído. Este é um passo de guarda de memory leaks. Não há risco real neste aplicativo porque o tempo de vida de um AstronautComponent é o mesmo que o tempo de vida do próprio aplicativo. Isso nem sempre seria verdade em um aplicativo mais complexo.

Não adicionamos essa proteção ao MissionControlComponent porque, como pai, ela controla a vida útil do MissionService.

Espero que isso ajude você.

Como a solução do seangwright (Edit 3) parece ser muito útil, eu também achei difícil empacotar esse recurso no componente base, e sugerir que outros colegas do projeto lembrem de chamar o super () no ngOnDestroy para ativar este recurso.

Esta resposta fornece uma maneira de se livrar da super chamada e tornar “componentDestroyed $” um núcleo do componente base.

 class BaseClass { protected componentDestroyed$: Subject = new Subject(); constructor() { /// wrap the ngOnDestroy to be an Observable. and set free from calling super() on ngOnDestroy. let _$ = this.ngOnDestroy; this.ngOnDestroy = () => { this.componentDestroyed$.next(); this.componentDestroyed$.complete(); _$(); } } /// placeholder of ngOnDestroy. no need to do super() call of extended class. ngOnDestroy() {} } 

E então você pode usar esse recurso livremente, por exemplo:

 @Component({ selector: 'my-thing', templateUrl: './my-thing.component.html' }) export class MyThingComponent extends BaseClass implements OnInit, OnDestroy { constructor( private myThingService: MyThingService, ) { super(); } ngOnInit() { this.myThingService.getThings() .takeUntil(this.componentDestroyed$) .subscribe(things => console.log(things)); } /// optional. not a requirement to implement OnDestroy ngOnDestroy() { console.log('everything works as intended with or without super call'); } } 

Baseado em: Usando Herança de Classe para conectar-se ao ciclo de vida do componente Angular 2

Outra abordagem genérica:

 export abstract class UnsubscribeOnDestroy implements OnDestroy { protected d$: Subject; constructor() { this.d$ = new Subject(); const f = this.ngOnDestroy; this.ngOnDestroy = () => { f(); this.d$.next(); this.d$.complete(); }; } public ngOnDestroy() { // no-op } } 

A resposta oficial do Edit # 3 (e variações) funciona bem, mas o que me causa é o ‘enlamear’ a lógica de negócios em torno da assinatura observável.

Aqui está outra abordagem usando wrappers.

Warining: código experimental

O arquivo subscribeAndGuard.ts é usado para criar uma nova extensão Observable para ngOnDestroy() e dentro dela para finalizar ngOnDestroy() .
O uso é o mesmo que .subscribe() , exceto por um primeiro parâmetro adicional referenciando o componente.

 import { Observable } from 'rxjs/Observable'; import { Subscription } from 'rxjs/Subscription'; const subscribeAndGuard = function(component, fnData, fnError = null, fnComplete = null) { // Define the subscription const sub: Subscription = this.subscribe(fnData, fnError, fnComplete); // Wrap component's onDestroy if (!component.ngOnDestroy) { throw new Error('To use subscribeAndGuard, the component must implement ngOnDestroy'); } const saved_OnDestroy = component.ngOnDestroy; component.ngOnDestroy = () => { console.log('subscribeAndGuard.onDestroy'); sub.unsubscribe(); // Note: need to put original back in place // otherwise 'this' is undefined in component.ngOnDestroy component.ngOnDestroy = saved_OnDestroy; component.ngOnDestroy(); }; return sub; }; // Create an Observable extension Observable.prototype.subscribeAndGuard = subscribeAndGuard; // Ref: https://www.typescriptlang.org/docs/handbook/declaration-merging.html declare module 'rxjs/Observable' { interface Observable { subscribeAndGuard: typeof subscribeAndGuard; } } 

Aqui está um componente com duas assinaturas, uma com o wrapper e outra sem. A única ressalva é que deve implementar OnDestroy (com o corpo vazio, se desejar), caso contrário Angular não sabe chamar a versão embrulhada.

 import { Component, OnInit, OnDestroy } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import 'rxjs/Rx'; import './subscribeAndGuard'; @Component({ selector: 'app-subscribing', template: '

Subscribing component is active

', }) export class SubscribingComponent implements OnInit, OnDestroy { ngOnInit() { // This subscription will be terminated after onDestroy Observable.interval(1000) .subscribeAndGuard(this, (data) => { console.log('Guarded:', data); }, (error) => { }, (/*completed*/) => { } ); // This subscription will continue after onDestroy Observable.interval(1000) .subscribe( (data) => { console.log('Unguarded:', data); }, (error) => { }, (/*completed*/) => { } ); } ngOnDestroy() { console.log('SubscribingComponent.OnDestroy'); } }

Uma demo plunker está aqui

Uma nota adicional: Re Edit 3 – A solução ‘Oficial’, isso pode ser simplificado usando takeWhile () ao invés de takeUntil () antes das inscrições, e um simples booleano ao invés de outro Observable em ngOnDestroy.

 @Component({...}) export class SubscribingComponent implements OnInit, OnDestroy { iAmAlive = true; ngOnInit() { Observable.interval(1000) .takeWhile(() => { return this.iAmAlive; }) .subscribe((data) => { console.log(data); }); } ngOnDestroy() { this.iAmAlive = false; } } 

Eu gosto das duas últimas respostas, mas experimentei um problema se a subclass fez referência a "this" em ngOnDestroy .

Eu modifiquei para ser isso, e parece que resolveu esse problema.

 export abstract class BaseComponent implements OnDestroy { protected componentDestroyed$: Subject; constructor() { this.componentDestroyed$ = new Subject(); let f = this.ngOnDestroy; this.ngOnDestroy = function() { // without this I was getting an error if the subclass had // this.blah() in ngOnDestroy f.bind(this)(); this.componentDestroyed$.next(true); this.componentDestroyed$.complete(); }; } /// placeholder of ngOnDestroy. no need to do super() call of extended class. ngOnDestroy() {} } 

Eu tentei a solução do Seangwright (Edit 3)

Isso não está funcionando para Observable que foi criado por timer ou intervalo.

No entanto, eu consegui trabalhar usando outra abordagem:

 import { Component, OnDestroy, OnInit } from '@angular/core'; import 'rxjs/add/operator/takeUntil'; import { Subject } from 'rxjs/Subject'; import { Subscription } from 'rxjs/Subscription'; import 'rxjs/Rx'; import { MyThingService } from '../my-thing.service'; @Component({ selector: 'my-thing', templateUrl: './my-thing.component.html' }) export class MyThingComponent implements OnDestroy, OnInit { private subscriptions: Array = []; constructor( private myThingService: MyThingService, ) { } ngOnInit() { const newSubs = this.myThingService.getThings() .subscribe(things => console.log(things)); this.subscriptions.push(newSubs); } ngOnDestroy() { for (const subs of this.subscriptions) { subs.unsubscribe(); } } } 

Você geralmente precisa cancelar a assinatura quando os componentes são destruídos, mas o Angular vai lidar com isso cada vez mais à medida que avançamos, por exemplo, na nova versão secundária do Angular4, eles têm essa seção para o cancelamento de assinatura do roteamento:

Você precisa cancelar a inscrição?

Conforme descrito na seção RoteiroAtivado: o balcão único para informações de rota da página Roteamento e Navegação, o Roteador gerencia os observáveis ​​que ele fornece e localiza as assinaturas. As assinaturas são limpas quando o componente é destruído, protegendo contra vazamentos de memory, portanto, você não precisa cancelar a assinatura da rota paramMap Observable.

Também o exemplo abaixo é um bom exemplo do Angular para criar um componente e destruí-lo depois, veja como o componente implementa o OnDestroy, se você precisar onInit, você também pode implementa-lo em seu componente, como implementa OnInit, OnDestroy

 import { Component, Input, OnDestroy } from '@angular/core'; import { MissionService } from './mission.service'; import { Subscription } from 'rxjs/Subscription'; @Component({ selector: 'my-astronaut', template: ` 

{{astronaut}}: {{mission}}

` }) export class AstronautComponent implements OnDestroy { @Input() astronaut: string; mission = ''; confirmed = false; announced = false; subscription: Subscription; constructor(private missionService: MissionService) { this.subscription = missionService.missionAnnounced$.subscribe( mission => { this.mission = mission; this.announced = true; this.confirmed = false; }); } confirm() { this.confirmed = true; this.missionService.confirmMission(this.astronaut); } ngOnDestroy() { // prevent memory leak when component destroyed this.subscription.unsubscribe(); } }

Following the answer by @seangwright , I’ve written an abstract class that handles “infinite” observables’ subscriptions in components:

 import { OnDestroy } from '@angular/core'; import { Subscription } from 'rxjs/Subscription'; import { Subject } from 'rxjs/Subject'; import { Observable } from 'rxjs/Observable'; import { PartialObserver } from 'rxjs/Observer'; export abstract class InfiniteSubscriberComponent implements OnDestroy { private onDestroySource: Subject = new Subject(); constructor() {} subscribe(observable: Observable): Subscription; subscribe( observable: Observable, observer: PartialObserver ): Subscription; subscribe( observable: Observable, next?: (value: any) => void, error?: (error: any) => void, complete?: () => void ): Subscription; subscribe(observable: Observable, ...subscribeArgs): Subscription { return observable .takeUntil(this.onDestroySource) .subscribe(...subscribeArgs); } ngOnDestroy() { this.onDestroySource.next(); this.onDestroySource.complete(); } } 

To use it, just extend it in your angular component and call the subscribe() method as follows:

 this.subscribe(someObservable, data => doSomething()); 

It also accepts the error and complete callbacks as usual, an observer object, or not callbacks at all. Remember to call super.ngOnDestroy() if you are also implementing that method in the child component.

Find here an additional reference by Ben Lesh: RxJS: Don’t Unsubscribe .

Another short addition to the above mentioned situations is:

  • Always unsubscribe, when new values in the subscribed stream is no more required or don’t matter, it will result in way less number of triggers and increase in performance in a few cases. Cases such as components where the subscribed data/event no more exists or a new subscription to an all new stream is required (refresh, etc.) is a good example for unsubscription.