RxJS
Last updated
Last updated
Es un paradigma que junto con el patrón Rx te ayudará a manejar mejor el flujo de información de una aplicación.
La programación reactiva se centra en flujos de información como secuencias ordenadas de datos.
La programación reactiva es un paradigma de programación que se centra en la creación de sistemas que responden automáticamente a los cambios en su entorno. En lugar de realizar tareas de forma secuencial, los programas reactivos están diseñados para responder rápidamente a eventos y cambios en el estado del sistema. Esto se logra mediante el uso de flujos de datos y programación asincrónica, lo que permite que los programas manejen múltiples entradas y salidas simultáneamente de manera eficiente.
En el contexto de la programación reactiva, un observador es un patrón de diseño que se utiliza para monitorear y responder a cambios en un flujo de datos.
Observable (Subject): Son colecciones de multiples valores de empuje (push) y evaluación (Lazy). Representan un flujo de datos que cambian en el tiempo y se comunican con los observadores usando los siguientes tres métodos:
Next: Cuando envía un dato.
Complete: Cuando deja de enviar datos.
Error: Cuando algo falla.
Observador (Observer): Es uno o mas consumidores de valores que se suscriben a un observable, se pueden comunicar a través de los métodos:
Subscribe: Para empezar a recibir valores.
Unsubscribe: Para dejar de recibir valores.
Los operadores son funciones puras, crean un nuevo observable de salida sin modificar el observable de entrada.
Operadores creacionales, son los que crean observables
Operadores pipeables, son los que se pueden encadenar a otros observables
Es un flujo de datos que emite una secuencia de eventos a lo largo del tiempo, emite los eventos que tiene de manera independiente para cada observador que se suscribe. Son unicast, emite valores solo cuando se suscribe.
Es un método que permite crear un Observable que recibe eventos determinados de un elemento del DOM.
Es un tipo de Observable que nos permite enviar los mismos valores de una fuente a todos los observadores además también nos permite insertar valores desde afuera del observable. Es multicast porque comparten los mismos valores entre multiples suscriptores.
Este tipo de observable, se puede conectar a otros observables por medio de pipes.
Es una variante de Subject que tiene una noción del valor actual que almacena y emite a todas las suscripciones nuevas. Este valor actual es el elemento emitido más recientemente por la fuente observable o un valor inicial/predeterminado si aún no se ha emitido ninguno. Dado que siempre debe haber un valor actual, BehaviorSubject requiere un valor inicial durante la inicialización. Subject y BehaviorSubject son observables únicos que actúan como observadores y observables a la vez.
from
y of
Los Observables from
y of
nos permiten generar observables a través de una serie de datos ya definidos.
of
genera un Observable a través de sus parámetros.
from
genera un Observable a través de un arreglo. asyncScheduler
como segundo argumento de from
envía los valores del observable al event loop queue.
Ejemplo para convertir una Promesa a Observable
pipe(): todos los operadores creacionales tienen este método, genera una cadena de operadores que se pueden enlazar uno tras otro.
map(): itera sobre los valores que obtenemos del observable transformándolos.
filter(): filtra los valores de un observable dada una condición.
reduce(): combina todos los valores emitidos por un observable a través de una función acumuladora.
La operación distinct
de RxJS devuelve un flujo de datos que emite sólo los valores distintos que recibe, eliminando duplicados.
Por ejemplo, si tenemos un flujo de números:
La salida en la consola sería:
La operación distinctUntilChanged
también devuelve un flujo de datos con valores únicos, pero sólo emite un valor cuando cambia el valor anterior recibido.
Por ejemplo, si tenemos un flujo de números:
La salida en la consola sería:
Como podemos ver, los números repetidos no se emiten, y sólo se emite el valor cuando cambia respecto al anterior.
Los operadores de tiempo nos ayudan a gestionar cómo y con qué frecuencia entregamos valores.
Hay muchos operadores de esta clase en RxJS, en esta clase te introduzco 4 de ellos:
¿Por qué son importantes los operadores de tiempo? Imagina que necesitamos consultar a una API por unos valores que tenemos. Si son muchos valores corremos el riesgo de utilizar muchos recursos o generar muchas peticiones y llegar a un límite establecido.
Pero a través de un operador como sampleTime
, sólo hacemos una petición a una API cada 1 minuto, o cada 10 minutos por los valores emitidos, disminuimos la frecuencia de peticiones y el riesgo de llegar a un límite.
Por ejemplo, si tenemos un flujo de eventos de teclado que emite una cadena de texto cada vez que el usuario escribe en un campo de entrada de texto, podríamos usar debounceTime
para retrasar la emisión de valores hasta que el usuario ha dejado de escribir por un tiempo determinado:
En este ejemplo, el flujo de eventos input$
emite un evento de teclado cada vez que el usuario escribe en el campo de entrada de texto. La operación debounceTime
retrasa la emisión de valores durante 500 milisegundos antes de enviar la cadena de texto a la salida del flujo de datos. Esto significa que si el usuario sigue escribiendo durante ese tiempo, el valor no se emitirá hasta que se haya detenido la escritura durante al menos 500 milisegundos.
De esta forma, podemos reducir la cantidad de actualizaciones innecesarias en nuestra aplicación y mejorar la experiencia del usuario.
Son operadores para fucionar a partir de uno o más observables.
mergeAll
→ Convierte un observable de orden superior en un observable de primer orden que entrega simultáneamente todos los valores que se emiten en los observables internos.
Observable de orden superior: Observable que emite otros observables.
mergeMap
→ Proyecta cada valor de fuente a un observable que se fusiona en la salida del observable. Es una mezcla entre mapear un observador y luego mezclar todos los valores que han sido emitidos.
La operación takeUntil
de RxJS se utiliza para cancelar la suscripción a un flujo de datos cuando se emite un valor en otro flujo de datos. En otras palabras, se utiliza para detener un flujo de datos cuando se cumple una cierta condición o evento.
La sintaxis básica de takeUntil
es la siguiente:
Donde source$
es el flujo de datos que se quiere detener, y notifier$
es el flujo de datos que emite un valor para indicar que se debe detener source$
.
Un caso de uso común para takeUntil
es cuando se quiere cancelar la suscripción a un flujo de datos cuando el componente o servicio asociado se destruye. En este caso, se puede crear un flujo de datos que emita un valor cuando se destruye el componente o servicio, y usar takeUntil
para cancelar la suscripción al flujo de datos principal.
Por ejemplo, si tenemos un flujo de intervalo que emite un valor cada segundo, pero queremos detenerlo cuando el componente se destruye, podríamos hacer lo siguiente:
En este ejemplo, creamos un flujo de intervalo que emite un valor cada segundo. Usamos takeUntil
para cancelar la suscripción a intervalo$
cuando se emite un valor en el flujo de destroy$
, que se emite cuando se destruye el componente mediante el método ngOnDestroy()
.
De esta manera, aseguramos que el flujo de datos intervalo$
se detenga cuando se destruye el componente, evitando problemas de memoria y pérdidas de rendimiento en nuestra aplicación.
Otras formas para desuscribir un observable:
https://rafaelneto.dev/blog/desuscribir-observable-behaviorsubject-angular/
Los operadores startWith
y endWith
de RxJS se utilizan para agregar valores iniciales o finales a un flujo de datos.
El operador startWith
agrega un valor inicial al inicio del flujo de datos, antes de cualquier otro valor que ya esté siendo emitido por el flujo.
El operador endWith
agrega un valor final al final del flujo de datos, después de cualquier otro valor que ya esté siendo emitido por el flujo.
La sintaxis básica de ambos operadores es la siguiente:
RxJS nos provee de operadores para manejar errores que pueden ocurrir en nuestro código.
catchError
: Captura errores en un observable retornando un nuevo observable o lanzando un error.
retry
: Reintenta ejecutar el observable cuando sucede un error. El número de reintentos lo puedes especificar.
⚠️ Recuerda que el orden de las funciones (en este caso operadores) importa al momento de manejar errores:
Si declaramos un operador como catchError
antes que un retry
, el operador retry
no se ejecutará. Por el contrario si declaramos retry
antes que catchError
podrían ejecutarse los dos.
Es una variante de Subject que tiene una noción del valor actual que almacena y emite a todas las suscripciones nuevas. Este valor actual es el elemento emitido más recientemente por la fuente observable o un valor inicial/predeterminado si aún no se ha emitido ninguno. Dado que siempre debe haber un valor actual, BehaviorSubject requiere un valor inicial durante la inicialización. Subject y BehaviorSubject son observables únicos que actúan como observadores y observables a la vez.