Operadores no tan comunes de Rxjs
Alex Córdoba
Posted on April 24, 2023
Después de dar un vistazo a los operadores comunes en Rxjs, esta vez es el turno de algunos operadores que no son tan comunes, tal vez desconocidos por algunos devs, pero muy utiles a la hora de agregar un comportamiento a nuestros Observables.
first
El operador first
es un operador de filtrado que emite solo el primer valor que se emite en la secuencia de entrada y luego completa la secuencia.
También es posible especificar una condición opcional para determinar el primero valor que se emite.
La forma general del operador first
es la siguiente:
first(predicate?: function): Observable
El argumento predicate
es una función que se usa para determinar el primero valor que se emite en la secuencia. Si no se proporciona ninguna función predicate
el operador first
emitirá el primero que se emita en la secuencia, teniendo el mismo comportamiento como si usáramos el operador take(1)
.
aqui hay un ejemplo:
import { interval } from 'rxjs'
import { first } from 'rxjs/operators';
const source = from([1, 2, 3, 4, 5]);
const example - source.pipe(
first(x => x > 2)
);
example.subscribe(console.log) // salida: 3
En este ejemplo, creamos un Observable
que emite los valores 1, 2, 3, 4, 5 y luego aplicamos el operador first
con una función predicate
que devuelve true
para el primer valor que sea mayor que 2. El primer valor que se emite en la secuencia que satisface la condición es 3, por lo que esa es la salida del subscribe
.
Es importante tener en cuenta que take
completará la secuencia después de emitir el primer valor, por lo que cualquier valor adicional que se emita después del primero valor se descartará. Si no se emite ningún valor que satisfaga la condición, el Observable
resultante no emitirá ningún valor.
takeWhile
El operador takeWhile
es un operador de filtrado que toma los valores emitidos por un Observable
hasta que se produce un valor que no satisface una condición especificada.
La forma general del operador takeWhile
es la siguiente:
takeWhile(predicate?: function, inclusive?: boolean): Observable
El argumento predicate
es una función que se utiliza para evaluar cada valor emitido por el Observable
. Si el valor emitido satisface la condición especificada, se incluirá en el resultado. Si el valor no satisface la condición, la suscripción se completará y se dejará de emitir valores.
El argumento opcional inclusive
se utiliza para incluir o excluir el valor que no cumple la condición especificada. Si inclusive
es true
, el valor que no cumple la condición se incluirá en la salida. Si inclusive
es false
el valor que no cumple la condición se excluye de la salida.
Por ejemplo:
import { of } from 'rxjs'
import { takeWhile } from 'rxjs/operators';
const source = of(1, 2, 3, 4, 5);
const example - source.pipe(
takeWhile(x => x < 4)
);
example.subscribe(console.log) // salida: 1, 2, 3
En este ejemplo, creamos un Observable
que emite los valores 1, 2, 3, 4, 5, luego aplicamos el operador takeWhile
con una función predicate
que evalúa si cada valor emitido es menor que 4. El operador takeWhile
incluirá los valores 1, 2 y 3 pero detendrá la emisión de valores después de que se emita el valor 4 que no cumple la condición.
También es posible usar el argumento opcional inclusive
para incluir o excluir el valor que no cumple la condición especificada. Por ejemplo:
import { of } from 'rxjs'
import { takeWhile } from 'rxjs/operators';
const source = of(1, 2, 3, 4, 5);
const example - source.pipe(
takeWhile(x => x < 4, true)
);
example.subscribe(console.log) // salida: 1, 2, 3, 4
Donde en este caso el valor 4 a pesar de que no cumple la condición sera emitido por el por el Observable
y detendrá la emisión de valores después de que se emita el valor 5 que no cumple la condición.
takeUntil
El operador takeUntil
es un operador de finalización que emite valores de un Observable
hasta que se emite un evento desde otro Observable
.
La forma general del operador takeWhile
es la siguiente:
takeUntil(notifier: Observable): Observable
El argumento notifier
es un Observable
que se utiliza para emitir un evento que indica que la emisión del Observable
de origen debe finalizar. Cuando el notifier
emite un valor o completa, el Observable
de origin se completa y ya no se emiten mas valores.
Esta seria su grifa de canicas:
Aquí hay un ejemplo:
import { interval, timer } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
const source = interval(1000);
const stopTimer = timer(5000);
const example = source.pipe(
takeUntil(stopTimer)
);
example.subscribe(console.log) // salida: 0, 1, 2, 3, 4
En este ejemplo, creamos un Observable
que emite valores cada segundo utilizando interval(1000)
, luego, creamos un Observable
que completa después de 5 segundos utilizando timer(5000)
. Finalmente, aplicamos el operador takeUntil
con el notifier
stopTimer
que completará la emisión del Observable
de origin después de 5 segundos.
El resultado es que solo se emiten los primeros 5 valores del Observable
de origen, ya que la emisión se detiene después de que el notifier
stopTimer
emite un valor y completa.
También podemos usar otros Observable
como notifier
para finalizar la emisión del Observable
de origen, como un botón pulsado, una respuesta de una API, una conexión de red que se interrumpe, etc.
skip
El operador skip
se utiliza para omitir los primeros elementos de un Observable
y emitir los restantes.
La forma general del operador skip
es la siguiente:
skip(count: number): Observable
El argumento count
es un número entero que indica el número de elementos que se deben omitir antes de comenzar a emitir elementos.
Esta es la grafica de canicas para el operador skip
:
Aqui un ejemplo:
import { of } from 'rxjs';
import { skip } from 'rxjs/operators';
const source = of(1, 2, 3, 4, 5);
const example = source.pipe(skip(3));
example.subscribe(console.log); // salida: 4, 5
En este ejemplo creamos un Observable
que emite los valores 1, 2, 3, 4, 5 utilizando of(1, 2, 3, 4, 5)
luego aplicamos el operador skip
con un valor de 3, lo que significa que se omitirán los primeros 3 valores. La salida del Observable
resultante es 4 y 5.
También podemos usar expresiones lógicas más complejas para determinar qué elementos se deben omitir. Por ejemplo, podríamos usar una expresión lambda que devuelve verdadero o falso en función de las propiedades de los elementos.
Es importante tener en cuenta que si el número de elementos a omitir es mayor o igual que el número total de elementos en el Observable
, el Observable
resultante sera vacío
distinct
El operador distinct
se utiliza para emitir solo los valores únicos de un Observable
omitiendo los valores que se han emitido previamente.
la forma general del operador distinct
es la siguiente:
distinct(keySelector?: (value: T) => K, flushes?: Observable<any>): Observable<T>
El argumento opcional keySelector
es una función que se utiliza para seleccionar una clave única para cada elemento. Si no se proporciona una función keySelector
se utiliza el propio valor como clave.
El argumento opcional flushes
es un Observable
que se utiliza para limpiar la caché de valores previamente emitidos.
Tomemos este ejemplo:
import { of } from 'rxjs';
import { distinct } from 'rxjs/operators';
const source = of(1, 2, 3, 1, 2, 4, 5, 3);
const example = source.pipe(distinct());
example.subscribe(console.log); // salida: 1, 2, 3, 4, 5
En este ejemplo creamos un Observable
que emite los valores 1, 2, 3, 1, 2, 4, 5, 3 utilizando of(1, 2, 3, 1, 2, 4, 5, 3)
luego, aplicamos el operador distinct
que omitirá los valores duplicados y emitirá solo los valores únicos. La salida del Observable
resultante es 1, 2, 3, 4, 5.
También podemos usar la función keySelector
para seleccionar una clave única basada en alguna propiedad o característica de los elementos. Por ejemplo, si tenemos un Observable
que emite objetos de usuario con una propiedad id
, podemos usar la función keySelector
para emitir solo los objetos de usuario con id
único:
import { of } from 'rxjs';
import { distinct } from 'rxjs/operators';
const users = [
{ id: 1, name: 'Alice },
{ id: 2, name: 'Bob },
{ id: 1, name: 'Charlie },
{ id: 3, name: 'David },
{ id: 2, name: 'Eve }
]
const source = of(users);
const example = source.pipe(distinct(user => user.id));
example.subscribe(console.log); // salida: { id: 1, name: 'Alice}, { id: 2, name 'Bob' }, { id: 3, name: 'David' }
En el ejemplo creamos un Observable
que emite los objetos de usuario definidos en el array users
. Luego, aplicamos el operador distinct
con una función keySelector
que selecciona la propiedad id
de cada objeto de usuario como clave única. La salida del Observable
resultante es solo los objetos de usuario con id
único: { id: 1, name: 'Alice}, { id: 2, name 'Bob' }, { id: 3, name: 'David' }.
Es importante tener en cuenta que el operador distinct
utiliza el cache interna para almacenar los valores emitidos previamente y determinar si un valor es único o no. Esto puede causar problemas de rendimiento si el Observable
emite.
También es importante resaltar que el operador distinct
utiliza el operador de equidad de triple igual ===
para comparar el valor emitido.
distinctUntilChanged
El operador distinctUntilChanged
se utiliza para emitir solo los valores que no son iguales al valor anterior emitido por el Observable
, es decir, si un valor se ha emitido previamente y es igual al valor actual, el valor actual se omite y no se emite.
La forma general del operador distinctUntilChanged
es la siguiente:
distinctUntilChanged(compareFn?: (x: T, y: T) => boolean): MonoTypeOperatorFunction<T>
El argumento opcional compareFn
es una función que se utiliza para comparar dos valores y determinar si son iguales o no. Si no se proporciona una función compareFn
, se utiliza el operador ===
para comparar valores.
Por ejemplo:
import { of } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
const source = of(1, 1, 2, 3, 3, 3, 4, 4, 5);
const example = source.pipe(distinctUntilChanged());
example.subscribe(console.log); // salida: 1, 2, 3, 4, 5
En este ejemplo creamos un Observable
que emite los valores 1, 1, 2, 3, 3, 3, 4, 4, 5 utilizando al función of
de rxjs, luego aplicamos el operador distinctUntilChanged
que omitirá los valores duplicados y emitirá solos los valores que no son iguales al valor anterior emitido. La salida del Observable
resultante es 1, 2, 3, 4, 5.
También podemos usar la función compareFn
para personalizar la comparación de valores. Por ejemplo si tenemos un Observable
que emite objetos de usuario con una propiedad name
, podemos usar la función compareFn
para omitir los objetos de usuario con el mismo nombre:
import { of } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
const users = [
{ id: 1, name: 'Alice },
{ id: 2, name: 'Bob },
{ id: 1, name: 'Bob },
{ id: 3, name: 'David },
{ id: 2, name: 'David }
]
const source = of(...users);
const example = source.pipe(distinctUntilChanged((ant, act) => ant.name === act.name));
example.subscribe(console.log); // salida: { id: 1, name: 'Alice}, { id: 2, name 'Bob' }, { id: 3, name: 'David' }
En este ejemplo creamos un Observable
que emite los objetos de usuario definidos en el array user
, luego, aplicamos el operador distinctUntilChanged
con una función compare
que compara solo los nombres de usuario de dos objetos consecutivos. La salida del Observable
resultante es solo los objetos de usuario cuyos nombres son diferentes a los del valor anterior: { id: 1, name: 'Alice}, { id: 2, name 'Bob' }, { id: 3, name: 'David' }
distinctUntilKeyChanged
El operador distinctUntilKeyChanged
se utiliza para emitir solo los valores que son diferentes al valor anterior, basándose en una clave especifica de los objetos emitidos. Es similar al operador distinctUntilChanged
, pero en lugar de comparar el valor completo emitido, solo compara el valor de una propiedad específica del objeto.
import { of } from 'rxjs';
import { distinctUntilKeyChanged } from 'rxjs/operators';
const users = [
{ id: 1, name: 'Alice },
{ id: 2, name: 'Bob },
{ id: 1, name: 'Bob },
{ id: 3, name: 'David },
{ id: 2, name: 'David }
]
const source = of(...users);
const example = source.pipe(distinctUntilKeyChanged('name');
example.subscribe(console.log); // salida: { id: 1, name: 'Alice}, { id: 2, name 'Bob' }, { id: 3, name: 'David' }
Como puedes ver, solo debemos especificar el key a comparar de los objetos emitido, en este caso el key es name y salida será { id: 1, name: 'Alice}, { id: 2, name 'Bob' }, { id: 3, name: 'David' }
Posted on April 24, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.