shareReplay - compartir caché
El operador shareReplay() proporciona multidifusión del mismo modo que share(), pero además recuerda un número especificado de valores anteriores y los pone a disposición de los suscriptores que se unan más tarde.
Esto permite casos de uso más avanzados, como almacenar en caché las respuestas de la API y compartir el estado.
Documentación oficial de RxJS - shareReplay()
🔰 Uso básico
import { interval } from 'rxjs';
import { take, shareReplay, tap } from 'rxjs';
// shareReplay(tamaño del búfer2)
const source$ = interval(1000).pipe(
take(5),
tap(value => console.log(`Fuente: ${value}`)),
shareReplay(2) // Más cercano2Almacenamiento en búfer de dos valores
);
// Primer abonado
console.log('Observer 1 Inicio de la suscripción');
source$.subscribe(value => console.log(`Observer 1: ${value}`));
// 3.5Segundos después2Añadir segundo abonado
setTimeout(() => {
console.log('Observer 2 Inicio de la suscripción - Último2Recibir dos valores');
source$.subscribe(value => console.log(`Observer 2: ${value}`));
}, 3500);Resultados de la ejecución
Observer 1 Inicio de la suscripción
Fuente: 0
Observer 1: 0
Fuente: 1
Observer 1: 1
Fuente: 2
Observer 1: 2
Fuente: 3
Observer 1: 3
Observer 2 Inicio de la suscripción - Último2Recibir dos valores
Observer 2: 2 // ← Valores históricos almacenados en buffer
Observer 2: 3 // ← Valores históricos almacenados en buffer
Fuente: 4
Observer 1: 4
Observer 2: 4PUNTO IMPORTANTE:.
- Los suscriptores perezosos también reciben inmediatamente los valores pasados almacenados en buffer
- Los valores se almacenan para el tamaño del búfer (dos en este ejemplo)
💡 sintaxis de shareReplay()
shareReplay(bufferSize?: number, windowTime?: number, scheduler?: SchedulerLike)
shareReplay(config: ShareReplayConfig)Parámetros.
import { interval } from 'rxjs';
import { take, shareReplay, tap } from 'rxjs';
// shareReplay(tamaño del búfer2)
const source$ = interval(1000).pipe(
take(5),
tap(value => console.log(`Fuente: ${value}`)),
shareReplay(2) // Más cercano2Almacenamiento en búfer de dos valores
);
// Primer abonado
console.log('Observer 1 Inicio de la suscripción');
source$.subscribe(value => console.log(`Observer 1: ${value}`));
// 3.5Segundos después2Añadir segundo abonado
setTimeout(() => {
console.log('Observer 2 Inicio de la suscripción - Último2Recibir dos valores');
source$.subscribe(value => console.log(`Observer 2: ${value}`));
}, 3500);Objeto de configuración (RxJS 7+)
interface ShareReplayConfig {
bufferSize?: number;
windowTime?: number;
refCount?: boolean; // Si un abonado es0Darse de baja cuando se conviertan
scheduler?: SchedulerLike;
}📊 Diferencia entre share y shareReplay
comportamiento de share()
import { interval } from 'rxjs';
import { take, share, tap } from 'rxjs';
const source$ = interval(1000).pipe(
take(3),
tap(value => console.log(`Fuente: ${value}`)),
share()
);
source$.subscribe(value => console.log(`Observer 1: ${value}`));
setTimeout(() => {
console.log('Observer 2 Inicio de la suscripción');
source$.subscribe(value => console.log(`Observer 2: ${value}`));
}, 1500);Resultados:.
Fuente: 0
Observer 1: 0
Fuente: 1
Observer 1: 1
Observer 2 Inicio de la suscripción
Fuente: 2
Observer 1: 2
Observer 2: 2 // ← Los valores pasados (0, 1) no se recibencomportamiento de shareReplay()
import { interval } from 'rxjs';
import { take, shareReplay, tap } from 'rxjs';
const source$ = interval(1000).pipe(
take(3),
tap(value => console.log(`Fuente: ${value}`)),
shareReplay(2) // Más cercano2Buffer un valor
);
source$.subscribe(value => console.log(`Observer 1: ${value}`));
setTimeout(() => {
console.log('Observer 2 Inicio de la suscripción');
source$.subscribe(value => console.log(`Observer 2: ${value}`));
}, 1500);Resultados:.
Fuente: 0
Observer 1: 0
Fuente: 1
Observer 1: 1
Observer 2 Inicio de la suscripción
Observer 2: 0 // ← Valores históricos almacenados en buffer
Observer 2: 1 // ← Valores históricos almacenados en buffer
Fuente: 2
Observer 1: 2
Observer 2: 2💼 Caso práctico.
1. Cachear las respuestas de la API.
import { Observable } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { map, shareReplay, tap } from 'rxjs';
interface User {
id: number;
name: string;
username: string;
email: string;
}
class UserService {
// Almacenar en caché la información del usuario
private userCache$ = ajax.getJSON<User>('https://jsonplaceholder.typicode.com/users/1').pipe(
tap(() => console.log('APIEjecutar solicitud')),
shareReplay({ bufferSize: 1, refCount: true }) // Último1Almacenar un valor (refCounty se libera cuando se cancelan todas las suscripciones)
);
getUser(): Observable<User> {
return this.userCache$;
}
}
const userService = new UserService();
// Primer componente
userService.getUser().subscribe(user => {
console.log('Componente1:', user);
});
// 2Segundos después otro componente
setTimeout(() => {
userService.getUser().subscribe(user => {
console.log('Componente2:', user); // ← Recuperado de la cachéAPISin solicitud
});
}, 2000);Resultados de la ejecución:.
import { interval } from 'rxjs';
import { take, shareReplay, tap } from 'rxjs';
// shareReplay(tamaño del búfer2)
const source$ = interval(1000).pipe(
take(5),
tap(value => console.log(`Fuente: ${value}`)),
shareReplay(2) // Más cercano2Almacenamiento en búfer de dos valores
);
// Primer abonado
console.log('Observer 1 Inicio de la suscripción');
source$.subscribe(value => console.log(`Observer 1: ${value}`));
// 3.5Segundos después2Añadir segundo abonado
setTimeout(() => {
console.log('Observer 2 Inicio de la suscripción - Último2Recibir dos valores');
source$.subscribe(value => console.log(`Observer 2: ${value}`));
}, 3500);2. compartir información de configuración
Resultados de la ejecución:.
3. caché de tiempo limitado
⚠️ Cuidado con las fugas de memoria
shareReplay()` mantiene el valor en un buffer y puede causar fugas de memoria si no se gestiona correctamente.
Código problemático.
import { interval } from 'rxjs';
import { take, shareReplay, tap } from 'rxjs';
// shareReplay(tamaño del búfer2)
const source$ = interval(1000).pipe(
take(5),
tap(value => console.log(`Fuente: ${value}`)),
shareReplay(2) // Más cercano2Almacenamiento en búfer de dos valores
);
// Primer abonado
console.log('Observer 1 Inicio de la suscripción');
source$.subscribe(value => console.log(`Observer 1: ${value}`));
// 3.5Segundos después2Añadir segundo abonado
setTimeout(() => {
console.log('Observer 2 Inicio de la suscripción - Último2Recibir dos valores');
source$.subscribe(value => console.log(`Observer 2: ${value}`));
}, 3500);Contramedidas recomendadas
🎯 Cómo elegir el tamaño del búfer
🔄 Operadores relacionados
- share() - multicast simple (sin buffer)
- publish() - control multicast de bajo nivel
- ReplaySubject](/es/guide/subjects/types-of-subject)** - Subject subyacente de shareReplay
Resumen.
El operador shareReplay() es,
- Almacenar en caché los valores anteriores y proporcionarlos también a los suscriptores perezosos
- Ideal para almacenar en caché las respuestas de la API
- Hay que tener cuidado con las fugas de memoria
- Seguro de usar con
refCounty `windowTime
Si necesita compartir o almacenar en caché el estado, shareReplay()` es una herramienta muy potente, pero es importante establecer tamaños de búfer y límites de tiempo apropiados.
🔗 Secciones relacionadas.
- Errores comunes y soluciones - Uso adecuado de shareReplay y prevención de fugas de memoria.
- share() - multicast simple
- ReplaySubject](/es/guide/subjects/types-of-subject)** - el Subject subyacente de shareReplay