Operadores no tan comunes de Rxjs
Tags: javascript, rxjs, spanish, webdev
Published: 2023-04-24 22:20:14


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:

```js
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:

```js
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:

```js
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: 

```js
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: 


```js
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:

```js
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:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v2ldsnnrs6pjr2d842af.png)


Aquí hay un ejemplo:

```js
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: 

```js
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`:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxjxubxlbsil3p4us48n.png)

Aqui un ejemplo:

```js
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: 

```js
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: 

```js
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:

```js
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:

```js
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: 

```js
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:

```js
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.

```js
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' }