En un art铆culo anterior , vimos c贸mo crear nuestras propias declaraciones RxJS. Ahora quiero hablar sobre un operador de creaci贸n poco conocido defer
, y explicar c贸mo puede usarlo en algunas situaciones.
Suponga que necesita crear un operador que tome una funci贸n y la ejecute solo una vez, la primera vez que recibe un valor. Lo implementamos bajo el nombre tapOnce
function tapOnce<T>(fn: Function): OperatorFunction<T, T> {
return function(source: Observable<any>) {
let run = false;
return source.pipe(
tap(() => {
if (!run) {
fn();
run = true;
}
})
);
};
}
El c贸digo es claro: se tap
usa para ejecutar la funci贸n, la bandera se run
necesita para hacer esto solo una vez. Ahora usamos el operador.
const source = interval(5000).pipe(
tapOnce(() => console.log('+')
));
source.subscribe(console.log);
Todo funciona, el signo m谩s se muestra en la consola solo en el primer emite. Ahora agregue los suscriptores.
const source = interval(5000).pipe(
tapOnce(() => console.log('+')
));
source.subscribe(console.log);
source.subscribe(console.log);
Si miras la consola, solo hay una ventaja. El problema es que ambos suscriptores usan el mismo entorno l茅xico y se refieren a la misma variable run
. Necesitamos una forma de posponer la creaci贸n de un hilo hasta que alguien se suscriba.
Ayudar谩 defer
import { defer } from 'rxjs';
function tapOnce<T>(fn: Function): OperatorFunction<T, T> {
return function(source: Observable<any>) {
return defer(() => {
let run = false;
return source.pipe(
tap(() => {
if (!run) {
fn();
run = true;
}
})
);
});
};
}
El operador defer
acepta una funci贸n que deber铆a regresar ObservableInput
. El c贸digo dentro defer
se ejecutar谩 solo despu茅s de la suscripci贸n, y no durante la creaci贸n. Usando este enfoque y gracias al cierre de js, cada suscriptor usa su propio entorno l茅xico.
Creemos nuestra implementaci贸n simple defer
para una mejor comprensi贸n.
function defer(observableFactory: () => ObservableInput<any>) {
return new Observable(subscriber => {
const source = observableFactory();
return source.subscribe(subscriber);
});
}
defer
devuelve una nueva secuencia, que se crea en el momento de la suscripci贸n por la funci贸n de f谩brica, y se utilizar谩 como fuente.
Aqu铆 hay m谩s ejemplos donde ser谩 煤til defer
. Digamos que tenemos una expresi贸n que debe contarse cuando alguien se registra. por ejemplo
const randNum = of(Math.random());
randNum.subscribe(console.log);
randNum.subscribe(console.log);
En este ejemplo, cada suscriptor recibir谩 el mismo valor aleatorio. Puede corregirlo para que la expresi贸n se cuente al suscribirse, no al anunciar.
const randNum = defer(() => of(Math.random()));
randNum2.subscribe(console.log);
randNum2.subscribe(console.log);
const randNum = () => of(Math.random());
randNum2().subscribe(console.log);
randNum2().subscribe(console.log);
Otro ejemplo es cuando necesita retrasar la ejecuci贸n de una promesa.
const promise = new Promise(resolve => {
resolve();
});
const promiseDefered = defer(() => {
return new Promise(resolve => {
resolve();
});
});
promiseDefered.subscribe(console.log);
Las promesas se ejecutan inmediatamente, independientemente del n煤mero de oyentes. Puede hacer que una promesa parezca una corriente (es decir, diferida) usando defer
.