La barrera de la depuraci�n
Cuando te enfrentas a problemas en RxJS como "los valores no fluyen", "aparecen valores diferentes a los esperados" o "podr�a haber una fuga de memoria", resolverlos puede llevar mucho tiempo si no conoces los m�todos de depuraci�n adecuados. Esta p�gina explica de manera integral las t�cnicas de depuraci�n espec�ficas de RxJS.
Estrategia b�sica de depuraci�n en RxJS
Los 5 pasos de la depuraci�n
Paso 1: Identificar el problema
Primero, clarifica qu� es el problema.
| S�ntoma | Posibles causas |
|---|---|
| No fluyen valores | Olvidaste subscribe, termina antes de complete, excluido por filter |
| No aparece el primer valor | combineLatest no cumple condici�n inicial, BehaviorSubject no configurado |
| El orden es extra�o | Uso de mergeMap, timing as�ncrono |
| Aparecen valores duplicados | M�ltiples subscribe sin share, mal uso de shareReplay |
| Hay fuga de memoria | Olvidaste unsubscribe, shareReplay con refCount: false |
| Los valores se retrasan | debounceTime, throttleTime, procesamiento as�ncrono |
Paso 2: Formular hip�tesis
Sup�n la causa del problema.
// Ejemplo: Problema de "no aparecen valores"
// Hip�tesis 1: �No hay subscribe?
// Hip�tesis 2: �complete/error demasiado temprano?
// Hip�tesis 3: �Excluido por filter?
// Hip�tesis 4: �Demora por procesamiento as�ncrono?Paso 3: Verificar con tap
Inserta tap en cada etapa para confirmar qu� est� ocurriendo realmente.
import { of } from 'rxjs';
import { map, filter, tap } from 'rxjs';
of(1, 2, 3, 4, 5).pipe(
tap(v => console.log('=5 Entrada:', v)),
filter(x => x > 10), // L Todos son excluidos
tap(v => console.log(' Pas� filter:', v)),
map(x => x * 10),
tap(v => console.log('=� Despu�s de map:', v))
).subscribe(result => {
console.log('=� Resultado:', result);
});
// Salida:
// =5 Entrada: 1
// =5 Entrada: 2
// =5 Entrada: 3
// =5 Entrada: 4
// =5 Entrada: 5
// (Ninguno pas� filter � filter es la causa)Escenarios comunes de depuraci�n
Escenario 1: Los valores no fluyen
Problema 1-1: Olvidaste subscribe
L Mal ejemplo: No hay subscribe
import { of } from 'rxjs';
import { map } from 'rxjs';
const result$ = of(1, 2, 3).pipe(
map(x => x * 10)
);
console.log('Completado'); // Se imprime inmediatamente
// No fluyen valores a result$ (porque no hay subscribe)Buen ejemplo: Hacer subscribe
import { of } from 'rxjs';
import { map } from 'rxjs';
const result$ = of(1, 2, 3).pipe(
map(x => x * 10)
);
result$.subscribe(value => {
console.log('Valor:', value);
});
console.log('Completado');
// Salida:
// Valor: 10
// Valor: 20
// Valor: 30
// CompletadoPuntos de verificaci�n
- Definir un Observable no hace nada
- Debes hacer subscribe obligatoriamente
- Si usas async pipe, subscribe no es necesario (Angular, etc.)
Problema 1-2: complete/error llega demasiado pronto
L Mal ejemplo: complete llega primero
import { EMPTY } from 'rxjs';
import { map } from 'rxjs';
EMPTY.pipe( // L complete inmediatamente
map(x => x * 10)
).subscribe({
next: value => console.log('Valor:', value),
complete: () => console.log('Completado')
});
// Salida:
// Completado
// (No fluye ning�n valor)Buen ejemplo: Verificar con tap
import { EMPTY } from 'rxjs';
import { map, tap } from 'rxjs';
EMPTY.pipe(
tap(() => console.log('=A Lleg� valor')), // Esto no se imprime
map(x => x * 10)
).subscribe({
next: value => console.log('Valor:', value),
complete: () => console.log('Completado')
});
// Salida:
// Completado
// (tap tampoco se ejecuta � EMPTY es la causa)Problema 1-3: Excluido por filter
L Mal ejemplo: Excluir todo sin darse cuenta
import { of } from 'rxjs';
import { filter } from 'rxjs';
of(1, 2, 3, 4, 5).pipe(
filter(x => x > 100) // L Todos excluidos
).subscribe(value => {
console.log('Valor:', value); // No se imprime nada
});Buen ejemplo: Verificar con tap
import { of } from 'rxjs';
import { filter, tap } from 'rxjs';
of(1, 2, 3, 4, 5).pipe(
tap(v => console.log('Antes de filter:', v)),
filter(x => x > 100),
tap(v => console.log('Despu�s de filter:', v)) // No se imprime ninguno
).subscribe(value => {
console.log('Valor:', value);
});
// Salida:
// Antes de filter: 1
// Antes de filter: 2
// Antes de filter: 3
// Antes de filter: 4
// Antes de filter: 5
// (No hay ninguno despu�s de filter � filter es demasiado estricto)Escenario 2: Aparecen valores diferentes a los esperados
Problema 2-1: Error de conversi�n de tipo
L Mal ejemplo: Confusi�n entre string y n�mero
import { of } from 'rxjs';
import { map } from 'rxjs';
const input = '5'; // string
of(input).pipe(
map(x => x + 10) // L '5' + 10 = '510' (concatenaci�n de strings)
).subscribe(result => {
console.log('Resultado:', result); // Resultado: 510
console.log('Tipo:', typeof result); // Tipo: string
});Buen ejemplo: Verificar tipo con tap
import { of } from 'rxjs';
import { map, tap } from 'rxjs';
const input = '5';
of(input).pipe(
tap(x => console.log('Entrada:', x, typeof x)),
map(x => Number(x)), // Convertir a n�mero
tap(x => console.log('Despu�s de conversi�n:', x, typeof x)),
map(x => x + 10)
).subscribe(result => {
console.log('Resultado:', result); // Resultado: 15
});Problema 2-2: Orden as�ncrono
L Mal ejemplo: El orden se desordena con mergeMap
import { of } from 'rxjs';
import { mergeMap, delay } from 'rxjs';
of(1, 2, 3).pipe(
mergeMap(x =>
of(x * 10).pipe(
delay(Math.random() * 1000) // Retraso aleatorio
)
)
).subscribe(value => {
console.log('Valor:', value);
});
// Ejemplo de salida (el orden no est� garantizado):
// Valor: 20
// Valor: 10
// Valor: 30Buen ejemplo: Garantizar el orden con concatMap
import { of } from 'rxjs';
import { concatMap, delay, tap } from 'rxjs';
of(1, 2, 3).pipe(
tap(x => console.log('Entrada:', x)),
concatMap(x =>
of(x * 10).pipe(
delay(Math.random() * 1000),
tap(v => console.log('Completado:', v))
)
)
).subscribe(value => {
console.log('Valor:', value);
});
// Salida (siempre en este orden):
// Entrada: 1
// Completado: 10
// Valor: 10
// Entrada: 2
// Completado: 20
// Valor: 20
// Entrada: 3
// Completado: 30
// Valor: 30Escenario 3: Detecci�n de fugas de memoria
Problema 3-1: Olvidaste unsubscribe
L Mal ejemplo: No hacer unsubscribe
import { interval } from 'rxjs';
class Component {
ngOnInit() {
interval(1000).subscribe(n => {
console.log('Valor:', n); // Se ejecuta eternamente
});
}
ngOnDestroy() {
// No hay unsubscribe � Fuga de memoria
}
}Buen ejemplo: Cancelaci�n autom�tica con takeUntil
import { interval, Subject } from 'rxjs';
import { takeUntil } from 'rxjs';
class Component {
private destroy$ = new Subject<void>();
ngOnInit() {
interval(1000).pipe(
takeUntil(this.destroy$)
).subscribe(n => {
console.log('Valor:', n);
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
console.log('Unsubscribe completado');
}
}Problema 3-2: Fuga de memoria con shareReplay
L Mal ejemplo: Fuga con refCount: false
import { interval } from 'rxjs';
import { shareReplay, take, tap } from 'rxjs';
const data$ = interval(1000).pipe(
take(100),
tap(n => console.log('Generando:', n)),
shareReplay({ bufferSize: 1, refCount: false })
// L refCount: false � Contin�a ejecut�ndose eternamente
);
const sub = data$.subscribe(n => console.log('Suscripci�n 1:', n));
setTimeout(() => {
sub.unsubscribe();
console.log('Unsubscribe hecho, pero contin�a ejecut�ndose internamente');
}, 5000);Buen ejemplo: Detenci�n autom�tica con refCount: true
import { interval } from 'rxjs';
import { shareReplay, take, tap } from 'rxjs';
const data$ = interval(1000).pipe(
take(100),
tap(n => console.log('Generando:', n)),
shareReplay({ bufferSize: 1, refCount: true })
// refCount: true � Se detiene al cancelar todas las suscripciones
);
const sub = data$.subscribe(n => console.log('Suscripci�n 1:', n));
setTimeout(() => {
sub.unsubscribe();
console.log('Unsubscribe � El stream tambi�n se detiene');
}, 5000);Herramientas y t�cnicas de depuraci�n
1. Depuraci�n gradual con tap
import { of } from 'rxjs';
import { map, filter, tap } from 'rxjs';
const debugTap = <T>(label: string, color: string = '=5') =>
tap<T>({
next: value => console.log(`${color} [${label}] next:`, value),
error: error => console.error(`L [${label}] error:`, error),
complete: () => console.log(` [${label}] complete`)
});
of(1, 2, 3, 4, 5).pipe(
debugTap('Entrada'),
filter(x => x % 2 === 0),
debugTap('Despu�s de filter', '=�'),
map(x => x * 10),
debugTap('Despu�s de map', '=�')
).subscribe({
next: value => console.log('=� Resultado final:', value),
complete: () => console.log('<� Completado')
});2. Operador de depuraci�n personalizado
import { tap, timestamp, map } from 'rxjs';
import { MonoTypeOperatorFunction } from 'rxjs';
interface DebugOptions {
label: string;
showTimestamp?: boolean;
showDiff?: boolean;
}
let lastTimestamp = 0;
function debug<T>(options: DebugOptions): MonoTypeOperatorFunction<T> {
const { label, showTimestamp = true, showDiff = true } = options;
return source => source.pipe(
timestamp(),
tap(({ value, timestamp }) => {
const parts = [`[${label}]`, value];
if (showTimestamp) {
parts.push(`@${new Date(timestamp).toISOString()}`);
}
if (showDiff && lastTimestamp > 0) {
const diff = timestamp - lastTimestamp;
parts.push(`(+${diff}ms)`);
}
console.log(...parts);
lastTimestamp = timestamp;
}),
map(({ value }) => value)
);
}
// Uso
import { interval } from 'rxjs';
import { take } from 'rxjs';
interval(500).pipe(
take(5),
debug({ label: 'Temporizador' }),
map(x => x * 10),
debug({ label: 'Despu�s de transformaci�n', showDiff: false })
).subscribe();3. RxJS DevTools (extensi�n de navegador)
M�todo de instalaci�n:
- Busca "RxJS DevTools" en Chrome/Edge Web Store
- A�ade la extensi�n
- Abre DevTools y haz clic en la pesta�a "RxJS"
Funciones principales:
- Monitoreo en tiempo real de todos los Observables
- Visualizaci�n con diagramas de m�rmol
- Seguimiento de subscribe/unsubscribe
- An�lisis de rendimiento
Ejemplo de uso:
import { interval } from 'rxjs';
import { map, take } from 'rxjs';
// Se detecta autom�ticamente en DevTools
const timer$ = interval(1000).pipe(
take(10),
map(x => x * 2)
);
timer$.subscribe(value => console.log(value));4. Depuraci�n de errores
Identificar d�nde ocurre el error
import { of, throwError } from 'rxjs';
import { map, catchError, tap } from 'rxjs';
of(1, 2, 3).pipe(
tap(v => console.log('1. Entrada:', v)),
map(x => {
if (x === 2) {
throw new Error('No se puede usar 2');
}
return x * 10;
}),
tap(v => console.log('2. Despu�s de map:', v)), // No se ejecuta en caso de error
catchError(error => {
console.error('3. Error capturado:', error.message);
return of(-1); // Devolver valor por defecto
}),
tap(v => console.log('4. Despu�s de catchError:', v))
).subscribe({
next: value => console.log('5. Resultado:', value),
error: error => console.error('Error de suscripci�n:', error),
complete: () => console.log('6. Completado')
});
// Salida:
// 1. Entrada: 1
// 2. Despu�s de map: 10
// 5. Resultado: 10
// 1. Entrada: 2
// 3. Error capturado: No se puede usar 2
// 4. Despu�s de catchError: -1
// 5. Resultado: -1
// 6. CompletadoDepuraci�n de rendimiento
Problema 1: Recalculaci�n excesiva
L Mal ejemplo: Recalculaci�n frecuente con combineLatest
import { BehaviorSubject, combineLatest } from 'rxjs';
import { map } from 'rxjs';
const a$ = new BehaviorSubject(1);
const b$ = new BehaviorSubject(2);
const c$ = new BehaviorSubject(3);
combineLatest([a$, b$, c$]).pipe(
map(([a, b, c]) => {
console.log('Ejecutando c�lculo pesado'); // Se ejecuta frecuentemente
return a + b + c;
})
).subscribe(result => console.log('Resultado:', result));
// Actualizaci�n frecuente
setInterval(() => {
a$.next(Math.random());
}, 100);Buen ejemplo: Excluir duplicados con distinctUntilChanged
import { BehaviorSubject, combineLatest } from 'rxjs';
import { map, distinctUntilChanged } from 'rxjs';
const a$ = new BehaviorSubject(1);
const b$ = new BehaviorSubject(2);
const c$ = new BehaviorSubject(3);
combineLatest([a$, b$, c$]).pipe(
map(([a, b, c]) => Math.floor(a) + Math.floor(b) + Math.floor(c)),
distinctUntilChanged(), // Pasa solo cuando el valor cambia
map(sum => {
console.log('Ejecutando c�lculo pesado'); // Solo cuando el valor cambia
return sum * 2;
})
).subscribe(result => console.log('Resultado:', result));
setInterval(() => {
a$.next(Math.random());
}, 100);Problema 2: Monitoreo del uso de memoria
import { interval } from 'rxjs';
import { scan, tap } from 'rxjs';
let itemCount = 0;
interval(100).pipe(
scan((acc, val) => {
acc.push(val);
itemCount = acc.length;
return acc;
}, [] as number[]),
tap(() => {
if (itemCount % 100 === 0) {
console.log(`N�mero de elementos: ${itemCount}`);
if (itemCount > 10000) {
console.warn('� Uso de memoria demasiado alto');
}
}
})
).subscribe();Problema 3: Monitoreo del n�mero de suscripciones
import { Observable, Subject } from 'rxjs';
class MonitoredSubject<T> extends Subject<T> {
private subscriptionCount = 0;
subscribe(...args: any[]): any {
this.subscriptionCount++;
console.log(`N�mero de suscripciones: ${this.subscriptionCount}`);
const subscription = super.subscribe(...args);
const originalUnsubscribe = subscription.unsubscribe.bind(subscription);
subscription.unsubscribe = () => {
this.subscriptionCount--;
console.log(`N�mero de suscripciones: ${this.subscriptionCount}`);
originalUnsubscribe();
};
return subscription;
}
}
// Uso
const data$ = new MonitoredSubject<number>();
const sub1 = data$.subscribe(v => console.log('Suscripci�n 1:', v));
const sub2 = data$.subscribe(v => console.log('Suscripci�n 2:', v));
sub1.unsubscribe();
sub2.unsubscribe();
// Salida:
// N�mero de suscripciones: 1
// N�mero de suscripciones: 2
// N�mero de suscripciones: 1
// N�mero de suscripciones: 0Lista de verificaci�n de depuraci�n
Si surge un problema, verifica lo siguiente en orden.
## Verificaci�n b�sica
- [ ] �Est�s llamando a `subscribe()`?
- [ ] �`complete` o `error` no llegan demasiado pronto?
- [ ] �Los valores no est�n siendo excluidos por `filter` o `take`?
- [ ] �Est�s esperando la finalizaci�n del procesamiento as�ncrono?
## Verificaci�n de timing
- [ ] �Entiendes sincron�a/asincron�a?
- [ ] �Verificaste el impacto de `delay`, `debounceTime`, `throttleTime`?
- [ ] �Se cumple la condici�n de primera emisi�n de `combineLatest`?
## Verificaci�n de memoria
- [ ] �Est�s usando `unsubscribe` o `takeUntil`?
- [ ] �Configuraste `refCount: true` en `shareReplay`?
- [ ] �Est�s delimitando adecuadamente los Observables infinitos?
## Verificaci�n de rendimiento
- [ ] �No hay recalculaci�n excesiva? (considera `distinctUntilChanged`)
- [ ] �El n�mero de suscripciones no aumenta demasiado?
- [ ] �Asincronizan los procesos pesados con `observeOn(asyncScheduler)`?Lista de verificaci�n de comprensi�n
Verifica si puedes responder a las siguientes preguntas.
## Depuraci�n b�sica
- [ ] Puedo depurar el flujo de valores usando tap
- [ ] Puedo identificar d�nde ocurren los errores
- [ ] Puedo verificar el timing de complete/error
## Uso de herramientas
- [ ] Conozco el uso b�sico de RxJS DevTools
- [ ] Puedo crear operadores de depuraci�n personalizados
- [ ] Puedo medir el timing usando timestamp
## Resoluci�n de problemas
- [ ] Puedo identificar la causa cuando no fluyen valores
- [ ] Puedo encontrar se�ales de fugas de memoria
- [ ] Puedo identificar problemas de rendimiento
## Prevenci�n
- [ ] Tengo el h�bito de depuraci�n gradual usando tap
- [ ] Implemento manejo de errores adecuadamente
- [ ] Conozco medidas contra fugas de memoriaPr�ximos pasos
Una vez que entiendas las t�cnicas de depuraci�n, integra todo el conocimiento aprendido hasta ahora y aprende patrones pr�cticos.
� Chapter 13: Colecci�n de patrones pr�cticos (en preparaci�n) - Colecci�n de patrones utilizables en el trabajo
P�ginas relacionadas
- Chapter 8: T�cnicas de depuraci�n de RxJS - Visi�n general de t�cnicas de depuraci�n
- Chapter 9: Pruebas de m�rmol - Depuraci�n con TestScheduler
- Comprensi�n del timing y orden - Depuraci�n usando tap
- Chapter 10: Errores comunes y soluciones - Evitar antipatrones
<� Ejercicios de pr�ctica
Problema 1: Identificar la causa cuando no fluyen valores
En el siguiente c�digo, identifica por qu� no se imprimen valores.
import { Subject, combineLatest } from 'rxjs';
const a$ = new Subject<number>();
const b$ = new Subject<number>();
combineLatest([a$, b$]).subscribe(([a, b]) => {
console.log('Valores:', a, b);
});
a$.next(1);
console.log('Completado');Respuesta
Causa
combineLatest no emite hasta que todos los streams emitan al menos un valor
Como b$ a�n no ha emitido un valor, solo a$.next(1) no provoca la emisi�n.
M�todo de correcci�n 1: Emitir valor tambi�n en b$
import { Subject, combineLatest } from 'rxjs';
const a$ = new Subject<number>();
const b$ = new Subject<number>();
combineLatest([a$, b$]).subscribe(([a, b]) => {
console.log('Valores:', a, b);
});
a$.next(1);
b$.next(2); // � Aqu� se emite
console.log('Completado');
// Salida:
// Valores: 1 2
// CompletadoM�todo de correcci�n 2: Usar BehaviorSubject
import { BehaviorSubject, combineLatest } from 'rxjs';
const a$ = new BehaviorSubject<number>(0); // Valor inicial
const b$ = new BehaviorSubject<number>(0);
combineLatest([a$, b$]).subscribe(([a, b]) => {
console.log('Valores:', a, b);
});
// Salida: Valores: 0 0 (emite inmediatamente)
a$.next(1);
// Salida: Valores: 1 0T�cnica de depuraci�n
Usando tap para verificar los valores de cada stream, puedes saber d�nde se detiene.
a$.pipe(tap(v => console.log('a$:', v)))
b$.pipe(tap(v => console.log('b$:', v)))Problema 2: Corregir la fuga de memoria
El siguiente c�digo tiene una fuga de memoria. Corr�gelo.
import { interval } from 'rxjs';
import { Component } from '@angular/core';
class MyComponent implements Component {
ngOnInit() {
interval(1000).subscribe(n => {
console.log('Temporizador:', n);
});
}
ngOnDestroy() {
console.log('Destruido');
}
}Ejemplo de respuesta
Problema
Al no hacer unsubscribe en ngOnDestroy, interval contin�a ejecut�ndose incluso despu�s de destruir el componente**
M�todo de correcci�n 1: Guardar Subscription y hacer unsubscribe
import { interval, Subscription } from 'rxjs';
class MyComponent {
private subscription!: Subscription;
ngOnInit() {
this.subscription = interval(1000).subscribe(n => {
console.log('Temporizador:', n);
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
console.log('Destruido y unsubscribe');
}
}M�todo de correcci�n 2: Usar takeUntil (recomendado)
import { interval, Subject } from 'rxjs';
import { takeUntil } from 'rxjs';
class MyComponent {
private destroy$ = new Subject<void>();
ngOnInit() {
interval(1000).pipe(
takeUntil(this.destroy$)
).subscribe(n => {
console.log('Temporizador:', n);
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
console.log('Destruido y unsubscribe');
}
}Puntos
- Los Observables infinitos como interval requieren unsubscribe obligatoriamente
- Se recomienda el patr�n takeUntil (permite gestionar m�ltiples suscripciones de forma unificada)
- En Angular, si usas async pipe, unsubscribe se hace autom�ticamente
Problema 3: Problema de orden
En el siguiente c�digo, explica por qu� el orden no est� garantizado y corr�gelo.
import { from, of } from 'rxjs';
import { mergeMap, delay } from 'rxjs';
from([1, 2, 3]).pipe(
mergeMap(x =>
of(x).pipe(
delay(Math.random() * 1000)
)
)
).subscribe(value => console.log(value));
// Ejemplo de salida: 2, 1, 3 (el orden no est� garantizado)Respuesta
Problema
mergeMap ejecuta en paralelo, por lo que el orden de finalizaci�n depende del tiempo de ejecuci�n**
M�todo de correcci�n: Usar concatMap
import { from, of } from 'rxjs';
import { concatMap, delay, tap } from 'rxjs';
from([1, 2, 3]).pipe(
tap(x => console.log('Inicio:', x)),
concatMap(x =>
of(x).pipe(
delay(Math.random() * 1000),
tap(v => console.log('Completado:', v))
)
)
).subscribe(value => console.log('Resultado:', value));
// Salida (siempre en este orden):
// Inicio: 1
// Completado: 1
// Resultado: 1
// Inicio: 2
// Completado: 2
// Resultado: 2
// Inicio: 3
// Completado: 3
// Resultado: 3Raz�n
- mergeMap: Ejecuci�n paralela, el orden de finalizaci�n no est� garantizado
- concatMap: Ejecuci�n secuencial, siempre emite en el mismo orden que la entrada
- switchMap: Solo el m�s reciente, procesos antiguos se cancelan
- exhaustMap: Ignora nuevos procesos durante la ejecuci�n
Comparaci�n con diagramas de m�rmol
Entrada: --1--2--3----|
mergeMap: --2--1--3--| (orden de finalizaci�n)
concatMap: --1--2--3-| (orden de entrada)Problema 4: Mejora de rendimiento
El siguiente c�digo recalcula frecuentemente. Mejora el rendimiento.
import { fromEvent } from 'rxjs';
import { map } from 'rxjs';
const input = document.querySelector('input')!;
fromEvent(input, 'input').pipe(
map(e => (e.target as HTMLInputElement).value),
map(value => {
console.log('Ejecutando c�lculo pesado');
return value.toUpperCase();
})
).subscribe(result => console.log(result));
// Usuario escribe "hello"
// Ejecutando c�lculo pesado (h)
// Ejecutando c�lculo pesado (he)
// Ejecutando c�lculo pesado (hel)
// Ejecutando c�lculo pesado (hell)
// Ejecutando c�lculo pesado (hello)Respuesta
M�todo de mejora 1: Esperar finalizaci�n de entrada con debounceTime
import { fromEvent } from 'rxjs';
import { map, debounceTime } from 'rxjs';
const input = document.querySelector('input')!;
fromEvent(input, 'input').pipe(
debounceTime(300), // Ejecuta si no hay entrada durante 300ms
map(e => (e.target as HTMLInputElement).value),
map(value => {
console.log('Ejecutando c�lculo pesado');
return value.toUpperCase();
})
).subscribe(result => console.log(result));
// Se ejecuta solo una vez despu�s de escribir "hello" y esperar 300msM�todo de mejora 2: Excluir duplicados con distinctUntilChanged
import { fromEvent } from 'rxjs';
import { map, debounceTime, distinctUntilChanged } from 'rxjs';
const input = document.querySelector('input')!;
fromEvent(input, 'input').pipe(
debounceTime(300),
map(e => (e.target as HTMLInputElement).value),
distinctUntilChanged(), // Ignorar si es el mismo valor que la vez anterior
map(value => {
console.log('Ejecutando c�lculo pesado');
return value.toUpperCase();
})
).subscribe(result => console.log(result));T�cnicas de mejora de rendimiento
- debounceTime: Esperar finalizaci�n de entrada
- throttleTime: Reducir a intervalos regulares
- distinctUntilChanged: Excluir duplicados
- observeOn(asyncScheduler): Asincronizar procesos pesados
- shareReplay: Cachear resultados