¿Necesita darse de baja de las llamadas http de Angular 2 para evitar pérdidas de memoria?
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
fuente
fuente
Respuestas:
Entonces la respuesta es no, no lo haces.
Ng2
lo limpiará solo.La fuente del servicio Http, de la fuente de back-end Http XHR de Angular:
Observe cómo se ejecuta
complete()
después de obtener el resultado. Esto significa que en realidad se da de baja al finalizar. Por lo tanto, no necesita hacerlo usted mismo.Aquí hay una prueba para validar:
Como se esperaba, puede ver que siempre se da de baja automáticamente después de obtener el resultado y terminar con los operadores observables. Esto sucede en un tiempo de espera (# 3) para que podamos verificar el estado del observable cuando todo esté hecho y completado.
Y el resultado
Por lo tanto, no existiría ninguna fuga, ya que se da de
Ng2
baja automáticamenteEs bueno mencionar: esto
Observable
se clasifica comofinite
, al contrario de loinfinite
Observable
que se puede emitir un flujo infinito de datos como DOMclick
oyente, por ejemplo.GRACIAS, @rubyboy por su ayuda en esto.
fuente
¿De qué están hablando?
OK, hay dos razones para darse de baja de cualquier observable. ¡Nadie parece estar hablando mucho sobre la muy importante segunda razón!
(Para HTTP, esto también cancelará la solicitud en el navegador, por lo que no perderá tiempo leyendo la respuesta. Pero eso es en realidad un aparte de mi punto principal a continuación).
La relevancia del número 2 dependerá de lo que haga su controlador de suscripción:
Considere algunos casos:
1) Un formulario de inicio de sesión. Ingresas nombre de usuario y contraseña y haces clic en 'Iniciar sesión'. ¿Qué sucede si el servidor es lento y decide presionar Escape para cerrar el cuadro de diálogo? Probablemente asumirás que no has iniciado sesión, pero si la solicitud http regresó después de presionar escape, entonces aún ejecutarás cualquier lógica que tengas allí. Esto puede dar lugar a una redirección a una página de cuenta, una cookie de inicio de sesión no deseada o una variable de token configurada. Probablemente esto no sea lo que esperaba su usuario.
2) Un formulario de 'enviar correo electrónico'.
Si el
subscribe
controlador para 'sendEmail' hace algo como activar una animación 'Se envía su correo electrónico', lo transfiere a una página diferente o intenta acceder a cualquier cosa que haya sido eliminada, puede obtener excepciones o comportamientos no deseados.También tenga cuidado de no asumir que
unsubscribe()
significa 'cancelar'. Una vez que el mensaje HTTP está en vuelounsubscribe()
NO cancelará la solicitud HTTP si ya ha llegado a su servidor. Solo cancelará la respuesta que vuelve a usted. Y el correo electrónico probablemente se enviará.Si crea la suscripción para enviar el correo electrónico directamente dentro de un componente de la interfaz de usuario, es probable que desee darse de baja al deshacerse, pero si el correo electrónico lo envía un servicio centralizado que no es la interfaz de usuario, entonces probablemente no necesite hacerlo.
3) Un componente angular que se destruye / cierra. Todos los observables http que aún se estén ejecutando en ese momento se completarán y ejecutarán su lógica a menos que cancele la suscripción
onDestroy()
. Si las consecuencias son triviales o no dependerá de lo que haga en el controlador de suscripción. Si intenta actualizar algo que ya no existe, puede recibir un error.A veces puede tener algunas acciones que desearía si el componente se elimina, y otras no. Por ejemplo, tal vez tenga un sonido 'swoosh' para un correo electrónico enviado. Probablemente desee que esto se reproduzca incluso si el componente estaba cerrado, pero si intenta ejecutar una animación en el componente, fallará. En ese caso, una solución condicional adicional dentro de la suscripción sería la solución, y NO querrás cancelar la suscripción del http observable.
Entonces, en respuesta a la pregunta real, no, no necesita hacerlo para evitar pérdidas de memoria. Pero debe hacerlo (a menudo) para evitar que se activen efectos secundarios no deseados al ejecutar código que pueda generar excepciones o corromper el estado de su aplicación.
Consejo:
Subscription
contiene unaclosed
propiedad booleana que puede ser útil en casos avanzados. Para HTTP, esto se establecerá cuando se complete. En Angular, puede ser útil en algunas situaciones establecer una_isDestroyed
propiedad en langDestroy
que su controlador pueda verificarlasubscribe
.Consejo 2: Si maneja múltiples suscripciones, puede crear un
new Subscription()
objeto ad-hoc yadd(...)
cualquier otra suscripción a él, por lo que cuando cancele la suscripción de la principal, también cancelará la suscripción de todas las suscripciones agregadas.fuente
Llamar al
unsubscribe
método es más bien cancelar una solicitud HTTP en curso ya que este método llama alabort
del objeto XHR subyacente y elimina los escuchas en los eventos de carga y error:Dicho esto,
unsubscribe
elimina a los oyentes ... Por lo tanto, podría ser una buena idea, pero no creo que sea necesario para una sola solicitud ;-)Espero que te ayude, Thierry
fuente
y = x.subscribe((x)=>data = x);
luego un cambio de usuario en las entradas yx.subscribe((x)=>cachlist[n] = x); y.unsubscribe()
oye, usaste los recursos de nuestro servidor, gané 'tirar a la basura ..... y en otro escenario: simplemente llame ay.stop()
tirar todo a la basuraDarse de baja es imprescindible si desea un comportamiento determinista en todas las velocidades de red.
Imagina que el componente A se representa en una pestaña: hace clic en un botón para enviar una solicitud 'OBTENER'. La respuesta tarda 200 ms en volver. Por lo tanto, puede cerrar la pestaña en cualquier momento sabiendo que la máquina será más rápida que usted y la respuesta http se procesará y se completará antes de que se cierre la pestaña y se destruya el componente A.
¿Qué tal en una red muy lenta? Al hacer clic en un botón, la solicitud 'OBTENER' tarda 10 segundos en recibir su respuesta, pero 5 segundos después de esperar, decide cerrar la pestaña. Eso destruirá el componente A para ser recolectado en un momento posterior. ¡Espera un minuto! , no cancelamos la suscripción; ahora, 5 segundos después, vuelve una respuesta y se ejecutará la lógica en el componente destruido. Esa ejecución ahora se considera
out-of-context
y puede dar lugar a muchas cosas, incluido un rendimiento muy bajo.Por lo tanto, la mejor práctica es usar
takeUntil()
y cancelar la suscripción de llamadas http cuando se destruye el componente.fuente
BehaviorSubject()
en su lugar y llamar simplementecomplete()
enngOnDestroy()
?BehaviourSubject
diferente?También con el nuevo módulo HttpClient, sigue siendo el mismo comportamiento
fuente
No debe darse de baja de los observables que se completa automáticamente (por ejemplo, Http, llamadas). Pero es necesario darse de baja de infinitos observables como
Observable.timer()
.fuente
Después de un tiempo de prueba, leer la documentación y el código fuente del 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/Universidad Angular: https://blog.angular-university.io/angular-http/
¿Y la respuesta a toda la cuestión de "NECESITO" darme de baja?
Depende. Las llamadas de memoria HTTP no son un problema. Los problemas son la lógica en sus funciones de devolución de llamada.
Por ejemplo: enrutamiento o inicio de sesión.
Si su llamada es una llamada de inicio de sesión, no tiene que "darse de baja", pero debe asegurarse de que si el Usuario abandona la página, maneje la respuesta correctamente en ausencia del usuario.
De molesto a peligroso
Ahora imagine que la red es más lenta de lo habitual, la llamada tarda más de 5 segundos y el usuario abandona la vista de inicio de sesión y se dirige a una "vista de soporte".
El componente puede no estar activo pero la suscripción. En caso de una respuesta, el usuario se redirigirá repentinamente (dependiendo de la implementación de handleResponse ()).
Esto no es bueno
También imagine que el usuario deja la PC, creyendo que aún no ha iniciado sesión. Pero su lógica inicia sesión en el usuario, ahora tiene un problema de seguridad.
¿Qué puedes hacer SIN darte de baja?
Haga que su llamada dependa del estado actual de la vista:
Usuario
.pipe(takeWhile(value => this.isActive))
para asegurarse de que la respuesta solo se maneja cuando la vista está activa.Pero, ¿cómo puede estar seguro de que la suscripción no está causando pérdidas de memoria?
Puede iniciar sesión si se aplica "teardownLogic".
Se llamará al teardownLogic de una suscripción cuando la suscripción esté vacía o cancelada.
No tiene que darse de baja. Debe saber si hay problemas en su lógica, que podrían causar problemas en su suscripción. Y cuídalos. En la mayoría de los casos, no será un problema, pero especialmente en tareas críticas como la autorización, debe tener cuidado con el comportamiento inesperado, ya sea con "darse de baja" u otra lógica como la canalización o las funciones de devolución de llamada condicional.
¿Por qué no siempre darse de baja?
Imagina que haces una solicitud de venta o publicación. El servidor recibe el mensaje de cualquier manera, solo la respuesta lleva un tiempo. Darse de baja, no deshacerá la publicación ni la pondrá. Pero cuando se da de baja, no tendrá la oportunidad de manejar la respuesta o informar al Usuario, por ejemplo, a través de Diálogo o un Brindis / Mensaje, etc.
Lo que hace que el usuario crea que la solicitud de poner / publicar no se realizó.
Entonces eso depende. Es su decisión de diseño, cómo lidiar con tales problemas.
fuente
Definitivamente deberías leer este artículo. Le muestra por qué siempre debe darse de baja incluso de http .
Actualizar
La afirmación anterior parece ser cierta, pero de todos modos, cuando la respuesta vuelve, la suscripción http se destruye de todos modos
fuente
Los observables RxJS están básicamente asociados y funcionan en consecuencia, lo suscribe. Cuando creamos el observable y el movimiento que lo completamos, el observable se cierra y cancela automáticamente.
Trabajan de la misma manera que los observadores pero con un orden bastante diferente. La mejor práctica para cancelar la suscripción cuando el componente se está destruyendo. Posteriormente podríamos hacerlo, por ejemplo. this. $ manageSubscription.unsubscibe ()
Si hemos creado el observable como la sintaxis mencionada a continuación, como
** return new Observable ((observador) => {** // Hace observable en estado frío ** observer.complete () **}) **
fuente