Table of Contents
- ¿Qué es rxjs?
- Ejemplo de uso teórico con
map()
,filter()
ytake()
- Ejemplo de uso práctico con
mergeMap()
ycatchError()
- Método 1 para suscripciones asíncronas:
async
pipe - Método 2 para suscripciones asíncronas: suscripción manual.
- Desuscripciones:
¿Qué es rxjs?
Angular como framework contiene muchísimas funcionalidades y librerías reactivas. Y una de ellas, si no la más importante o la que más se usa, es Rxjs.
RxJS es una librería de JavaScript que se utiliza para programación reactiva. La programación reactiva es un paradigma de programación que se centra en el flujo de datos y la propagación de cambios. RxJS se basa en el patrón Observador (Observer) y proporciona una forma eficiente y eficaz de trabajar con flujos de datos asíncronos, como eventos, solicitudes HTTP, y otros tipos de datos que cambian con el tiempo.
RxJS se basa en el concepto de "observables".
Los observables son secuencias de eventos o datos que pueden ser observados y reaccionados a medida que se emiten. Los observables pueden ser operados y transformados de diversas maneras para realizar tareas como filtrar datos, mapearlos, combinarlos, o manejar errores de manera elegante.
La biblioteca Rxjs es especialmente útil en aplicaciones web y móviles donde la interacción del usuario, las notificaciones de eventos, y las llamadas a servicios web son comunes. Al adoptar Rxjs, los desarrolladores pueden escribir código más limpio y mantenible para manejar de manera eficiente flujos de datos asíncronos y reactivos.
Vamos, de forma resumida, RxJS es una biblioteca de JavaScript que facilita la programación reactiva al proporcionar una amplia gama de herramientas y operadores para trabajar con flujos de datos asíncronos de una manera más eficiente y manejable.
map()
, filter()
y take()
Ejemplo de uso teórico con En el ejemplo que muestro a continuación importamos from
, of
,interval
de rxj
, que nos permitirán convertir datos en observables. También importamos map
, filter
y take
de la carpeta de operadores de rxjs, de forma que podamos mapear o filtrar los observables que hayamos creado.
mergeMap()
y catchError()
Ejemplo de uso práctico con Puedes utilizar mergeMap
para manejar solicitudes HTTP anidadas, como cuando necesitas cargar datos dependiendo de los resultados de otra solicitud. Por ejemplo, supongamos que tienes una solicitud inicial para obtener un usuario y luego deseas obtener las tareas de ese usuario:
De igual forma, puedes utilizar el operador catchError
para manejar errores de observables, como errores en solicitudes HTTP. Por ejemplo, si deseas mostrar un mensaje de error cuando una solicitud falla:
async
pipe
Método 1 para suscripciones asíncronas: El operador async
en Angular es una característica que se utiliza para simplificar la gestión de observables en las plantillas de tus componentes. Básicamente, permite que Angular se encargue de suscribirse y desuscribirse automáticamente de los observables, lo que reduce la necesidad de gestionar manualmente la suscripción y desuscripción en tus componentes. El uso principal del operador async
es en las plantillas, especialmente en el contexto de Angular.
Principales ventajas:
- Uso en plantillas: En lugar de suscribirte manualmente en el componente y asignar los datos a propiedades del componente, puedes usar
async
directamente en la plantilla para mostrar los datos. - Manejo automático de la suscripción y desuscripción: Cuando utilizas
async
en una plantilla, Angular se encarga automáticamente de suscribirse al observable cuando se muestra la vista y de desuscribirse cuando se destruye la vista o se cambia el componente. Esto evita problemas de fuga de memoria y garantiza que la suscripción se gestione de manera segura y eficiente. - Actualización automática: Cuando el observable emite nuevos valores, la vista se actualizará automáticamente para reflejar esos cambios, sin necesidad de escribir código adicional.
¡De esta forma pasamos directamente el observable al template y nos olvidamos de la desuscripción!
Método 2 para suscripciones asíncronas: suscripción manual.
En general, el uso del operador async
es muy recomendable, ya que automatiza la gestión de suscripciones y desuscripciones, lo que simplifica considerablemente el código y ayuda a evitar problemas como las fugas de memoria.
Sin embargo, en algunos casos particulares, puede ser necesario realizar la suscripción manualmente, por ejemplo, cuando necesitas un mayor control sobre la lógica de suscripción o cuando trabajas con observables más complejos.
A continuación, te proporcionaré un ejemplo en el que la suscripción debe ser manual porque la lógica de manejo de eventos específicos es más compleja de lo que el operador async
puede manejar de manera directa.
Supongamos que estás trabajando con un observable de eventos de ratón en Angular y deseas realizar una lógica personalizada para procesar estos eventos. Aquí hay un ejemplo en el que necesitas realizar la suscripción manualmente:
En este ejemplo:
- Creamos un componente que tiene un elemento HTML que queremos seguir con el ratón.
- Usamos
fromEvent
para crear un observable de eventos de ratón en ese elemento. - Realizamos la suscripción manualmente en el método
**ngAfterViewInit**
, lo que nos permite personalizar la lógica para mover el elemento div en respuesta a eventos de ratón. - Nos desuscribimos en el método
ngOnDestroy
para evitar fugas de memoria.
En este escenario, es necesario realizar la suscripción manualmente ya que estamos implementando una lógica personalizada para manejar los eventos de ratón. El operador async
no es adecuado en este caso, ya que no nos proporciona suficiente control sobre el comportamiento del elemento.
Desuscripciones:
Como comentaba anteriormente, una de las prácticas recomendadas a la hora de programar es desuscribirnos de todos aquellos observables. De esta forma conseguimos:
- Liberación de recursos: Cuando te suscribes a un observable, se establece una conexión para escuchar eventos o recibir datos. Si no te desuscribes cuando ya no necesitas los datos, la conexión seguirá activa, lo que podría consumir recursos innecesarios como memoria y poder de procesamiento.
- Prevención de pérdida de memoria: Las suscripciones no desechadas pueden llevar a una fuga de memoria en tu aplicación. Si no te desuscribes, los observables y los objetos relacionados pueden quedar en memoria incluso cuando ya no se utilizan. Esto puede hacer que tu aplicación se vuelva más lenta con el tiempo y, en casos extremos, agotar la memoria y hacer que la aplicación se bloquee.
- Mantenimiento del estado consistente: En aplicaciones donde se gestionan estados, como las aplicaciones Angular, una suscripción no desuscrita puede llevar a un estado inconsistente. Puedes recibir datos que cambian el estado de la aplicación, y si no se desuscribe adecuadamente, es posible que tu aplicación se comporte de manera inesperada.
- Evitar comportamientos no deseados: En situaciones donde una suscripción está vinculada a un componente o servicio específico, la falta de desuscripción puede causar comportamientos inesperados cuando se cambia de componente o se destruye un componente.
- Reducción de errores potenciales: Al desuscribirte adecuadamente, reduces la posibilidad de errores o comportamientos inesperados en tu aplicación. Las suscripciones no desechadas pueden causar efectos secundarios no deseados y dificultar la depuración.
async
pipe).
Usando el propio ciclo de vida del componente (Cuando hacemos uso del pipe async
no necesitamos realizar ninguna desuscripción manual desde nuestro componente.
unsubscribe()
Método Cada suscripción a un observable en RxJS retorna un objeto Subscription. Puedes llamar al método unsubscribe()
en este objeto para desuscribirte de la suscripción cuando se produzca el ciclo de vida ngOnDestroy
del componente. Sin embargo, esto genera problemas de boilerplate
Por ejemplo:
takeUntil()
Usando el operador Puedes usar el operador takeUntil()
en combinación con otro observable que emita un valor para indicar cuándo deseas desuscribirte. Aquí tienes un ejemplo:
AutoUnsubscribe()
Función Esta es, en mi opinión, la forma más elegante de controlar las suscripciones de forma global en nuestra aplicación. Observa el código con detenimiento y después lee la explicación:
Esta función es un decorador en TypeScript que se utiliza para automatizar la desuscripción de observables en componentes; acepta un parámetro opcional blacklist
, que es una matriz de nombres de propiedades que se deben excluir de la desuscripción automática.
Cuando aplicas este decorador a una clase de componente de Angular, reemplaza el método ngOnDestroy
del componente con una versión personalizada. Esta versión personalizada del método ngOnDestroy
se encarga de recorrer todas las propiedades del componente y desuscribir cualquier observable presente en esas propiedades, a menos que el nombre de la propiedad esté en la lista negra especificada en el parámetro blacklist
. Aquí está el flujo de lo que hace la función:
- Reemplaza el método
ngOnDestroy
del componente con una función personalizada. - En la función personalizada, itera sobre todas las propiedades del componente utilizando un bucle
for...of
. - Para cada propiedad, verifica si no está en la lista negra (
blacklist
) especificada. - Si la propiedad no está en la lista negra, comprueba si es un objeto y si tiene un método
unsubscribe
. Si ambas condiciones se cumplen, llama al métodounsubscribe
en esa propiedad para desuscribirse. - Luego, verifica si el método
ngOnDestroy
original existía y era una función antes de llamarlo. Esto es importante porque si el componente tenía unngOnDestroy
original, aún se ejecutará después de desuscribirse de los observables. - Llama al método
ngOnDestroy
original si existe y era una función, pasándole los mismos argumentos que se le pasaron a la función personalizada.
AutoUnsubscribe
es útil para automatizar la desuscripción de observables en componentes de Angular, evitando así posibles fugas de memoria causadas por observables no desuscritos adecuadamente. Además, proporciona una lista negra opcional para excluir propiedades específicas de la desuscripción automática si es necesario.
Y ya está. 🚀
Automáticamente cuando el componente de destruya se ejecutará la función y se desuscribirá, evitando así problemas de memoria.
Te recomiendo que visites la documentación oficial de RxJS para ver el funcionamiento y todos los operadores disponibles: https://rxjs.dev/api
Si te ha gustado este artículo no dudes en compartirlo en tus redes. 😊
Échale un vistazo a mi blog, donde podrás encontrar más artículos sobre Angular.