Você precisa cancelar a inscrição nas chamadas http do Angular 2 para evitar vazamento de memória?
fetchFilm(index) {
var sub = this._http.get(`http://example.com`)
.map(result => result.json())
.map(json => {
dispatch(this.receiveFilm(json));
})
.subscribe(e=>sub.unsubscribe());
...
angular
memory-leaks
rxjs
angular2-http
born2net
fonte
fonte
Respostas:
Então a resposta é não, você não.
Ng2
irá limpá-lo em si.A fonte de serviço Http, da fonte de back-end Http XHR da Angular:
Observe como ele é executado
complete()
depois de obter o resultado. Isso significa que ele realmente cancela a inscrição ao concluir. Então você não precisa fazer isso sozinho.Aqui está um teste para validar:
Como esperado, você pode ver que ele é sempre cancelado automaticamente após obter o resultado e terminar com os operadores observáveis. Isso acontece em um tempo limite (nº 3) para que possamos verificar o status do observável quando tudo estiver pronto e concluído.
E o resultado
Portanto, não haveria vazamento como
Ng2
cancelamento automático de inscrição!É bom mencionar: isso
Observable
é classificado comofinite
, ao contrário doinfinite
Observable
que é um fluxo infinito de dados que pode ser emitido como DOMclick
ouvinte por exemplo.OBRIGADO, @rubyboy pela ajuda.
fonte
Sobre o que vocês estão falando!!!
OK, então há duas razões para cancelar a inscrição de qualquer observável. Ninguém parece estar falando muito sobre a segunda razão muito importante!
(Para HTTP, isso na verdade também cancelará a solicitação no navegador - para que não perca tempo lendo a resposta. Mas isso é um aparte do meu ponto principal abaixo.)
A relevância do número 2 dependerá do que o manipulador de assinaturas fizer:
Considere alguns casos:
1) Um formulário de login. Você digita o nome de usuário e a senha e clica em 'Login'. E se o servidor estiver lento e você decidir pressionar Escape para fechar a caixa de diálogo? Provavelmente, você presumirá que não estava logado, mas se a solicitação http retornar depois de pressionar escape, você ainda executará a lógica que tiver lá. Isso pode resultar em um redirecionamento para uma página da conta, sendo definido um cookie de login indesejado ou uma variável de token. Provavelmente não é o que seu usuário esperava.
2) Um formulário 'enviar email'.
Se o
subscribe
manipulador de 'sendEmail' fizer algo como acionar uma animação 'Seu email é enviado', transfira você para uma página diferente ou tente acessar qualquer coisa que tenha sido descartada, você pode receber exceções ou comportamentos indesejados.Também tome cuidado para não assumir que
unsubscribe()
significa 'cancelar'. Uma vez que a mensagem HTTP esteja em andamentounsubscribe()
, NÃO cancelará a solicitação HTTP se já tiver atingido seu servidor. Ele apenas cancelará a resposta retornando para você. E o email provavelmente será enviado.Se você criar a assinatura para enviar o email diretamente dentro de um componente da interface do usuário, provavelmente desejará cancelar a inscrição ao descartar, mas se o email estiver sendo enviado por um serviço centralizado que não seja a UI, provavelmente não será necessário.
3) Um componente angular que é destruído / fechado. Quaisquer http observáveis ainda em execução no momento concluirão e executarão sua lógica, a menos que você cancele a inscrição em
onDestroy()
. Se as consequências são triviais ou não, dependerá do que você faz no manipulador de assinaturas. Se você tentar atualizar algo que não existe mais, poderá receber um erro.Às vezes, você pode ter algumas ações que deseja se o componente for descartado e outras não. Por exemplo, talvez você tenha um som de "swoosh" para um email enviado. Você provavelmente deseja que isso seja reproduzido, mesmo que o componente esteja fechado, mas se você tentar executar uma animação no componente, ela falhará. Nesse caso, uma lógica condicional extra dentro da assinatura seria a solução - e você NÃO deseja cancelar a assinatura do http observável.
Portanto, em resposta à pergunta real, não, você não precisa fazer isso para evitar vazamentos de memória. Mas você precisa fazer isso (frequentemente) para evitar que efeitos colaterais indesejados sejam acionados executando um código que pode gerar exceções ou corromper o estado do aplicativo.
Dica: O
Subscription
contém umaclosed
propriedade booleana que pode ser útil em casos avançados. Para HTTP, isso será definido quando for concluído. Em Angular, pode ser útil em algumas situações definir uma_isDestroyed
propriedade nangDestroy
qual possa ser verificada pelo seusubscribe
manipulador.Dica 2: Se estiver lidando com várias assinaturas, você poderá criar um
new Subscription()
objeto ad-hoc eadd(...)
quaisquer outras assinaturas - portanto, ao cancelar a assinatura do principal, ele também cancelará a assinatura de todas as assinaturas adicionadas.fonte
Chamar o
unsubscribe
método é, em vez disso, cancelar uma solicitação HTTP em andamento, pois esse método chama a queabort
está no objeto XHR subjacente e remove ouvintes nos eventos de carregamento e erro:Dito isto,
unsubscribe
remove os ouvintes ... Portanto, pode ser uma boa ideia, mas não acho que seja necessário para uma única solicitação ;-)Espero que ajude você, Thierry
fonte
y = x.subscribe((x)=>data = x);
então uma mudança de usuário nas entradas ex.subscribe((x)=>cachlist[n] = x); y.unsubscribe()
ei você usou nossos recursos de servidor, eu ganhei jogue você fora ..... e em outro cenário: basta chamary.stop()
jogar tudo foraCancelar a inscrição é uma obrigação se você quiser um comportamento determinístico em todas as velocidades da rede.
Imagine que o componente A é renderizado em uma guia - Você clica em um botão para enviar uma solicitação 'GET'. Leva 200 ms para a resposta voltar. Portanto, você pode fechar a guia a qualquer momento sabendo que a máquina será mais rápida do que você e a resposta http será processada e concluída antes que a guia seja fechada e o componente A seja destruído.
Que tal uma rede muito lenta? Você clica em um botão, a solicitação 'GET' leva 10 segundos para receber sua resposta, mas, em 5 segundos, você decide fechar a guia. Isso destruirá o componente A para ser coletado no lixo posteriormente. Espere um minuto! , não cancelamos a inscrição - agora 5 segundos depois, uma resposta volta e a lógica no componente destruído será executada. Essa execução agora é considerada
out-of-context
e pode resultar em várias coisas, incluindo desempenho muito baixo.Portanto, a melhor prática é usar
takeUntil()
e cancelar a inscrição de chamadas http quando o componente é destruído.fonte
BehaviorSubject()
em vez disso e chamar apenascomplete()
nongOnDestroy()
?BehaviourSubject
seria diferente?Também com o novo módulo HttpClient, permanece o mesmo comportamento
fonte
Você não deve cancelar a assinatura de observáveis que são concluídos automaticamente (por exemplo, Http, chamadas). Mas é necessário cancelar a inscrição de infinitos observáveis como
Observable.timer()
.fonte
Depois de um tempo de teste, a leitura da documentação e o código fonte do HttpClient.
HttpClient:
https://github.com/angular/angular/blob/master/packages/common/http/src/client.tsHttpXhrBackend :
https://github.com/angular/angular/blob/master/packages/common/http/src/xhr.tsHttpClientModule
: https://indepth.dev/exploring-the-httpclientmodule-in-angular/Universidade Angular: https://blog.angular-university.io/angular-http/
E a resposta para toda a edição de "eu preciso" cancelar a inscrição?
Depende. Chamada HTTP Memoryleaks não é um problema. Os problemas são a lógica nas suas funções de retorno de chamada.
Por exemplo: Roteamento ou Login.
Se a sua ligação for de login, você não precisará "cancelar a inscrição", mas precisará garantir que, se o Usuário sair da página, lide com a resposta adequadamente na ausência do usuário.
De irritante a perigoso
Agora, imagine, a rede está mais lenta que o normal, a chamada leva mais 5 segundos e o usuário sai da visualização de login e passa para uma "visualização de suporte".
O componente pode não estar ativo, mas a assinatura. No caso de uma resposta, o usuário será redirecionado repentinamente (dependendo da sua implementação handleResponse ()).
Isso não é bom.
Imagine também que o usuário saia do PC, acreditando que ainda não está logado. Mas você lógico faz logon no usuário, agora você tem um problema de segurança.
O que você pode fazer SEM cancelar a inscrição?
Faça sua ligação dependente do estado atual da exibição:
Usuário
.pipe(takeWhile(value => this.isActive))
para garantir que a resposta seja tratada apenas quando a exibição estiver ativa.Mas como você pode ter certeza de que a assinatura não está causando falta de memória?
Você pode registrar se o "teardownLogic" for aplicado.
O teardownLogic de uma assinatura será chamado quando a subscrição estiver vazia ou sem assinatura.
Você não precisa cancelar a inscrição. Você deve saber se há problemas em sua lógica que podem causar problemas em sua assinatura. E cuide deles. Na maioria dos casos, isso não será um problema, mas principalmente em tarefas críticas como a autorização, você deve cuidar de um comportamento inesperado, seja com "cancelamento de inscrição" ou com outra lógica, como funções de canal ou retorno de chamada condicional.
por que não sempre cancelar a inscrição?
Imagine que você faça uma solicitação de colocação ou publicação. O servidor recebe a mensagem de qualquer maneira, apenas a resposta demora um pouco. Cancelar a inscrição, não desfará a postagem nem a coloca. Porém, ao cancelar a inscrição, você não terá a chance de lidar com a resposta ou informar o Usuário, por exemplo, via Caixa de Diálogo ou um Toast / Message etc.
O que faz com que o usuário acredite que a solicitação de put / post não foi feita.
Então depende. É sua decisão de design, como lidar com esses problemas.
fonte
Você definitivamente deve ler este artigo. Ele mostra por que você deve sempre cancelar a inscrição, mesmo de http .
Atualizar
A afirmação acima parece verdadeira, mas de qualquer maneira, quando a resposta voltar, a assinatura http será destruída de qualquer maneira
fonte
O RxJS observável é basicamente associado e funciona de acordo com a sua assinatura. Quando criamos o observável e o movimento que o completamos, o observável é automaticamente fechado e cancelado.
Eles trabalham da mesma maneira que os observadores, mas com uma ordem bem diferente. A melhor prática para cancelar a inscrição quando o componente estiver sendo destruído. Poderíamos fazer isso posteriormente, por exemplo. this. $ manageSubscription.unsubscibe ()
Se criamos a sintaxe observável como abaixo mencionada, como
** retorna new Observable ((observador) => {** // Torna observável em estado frio ** observer.complete () **}) **
fonte