This project demonstrates three different caching patterns in Angular using RxJS, with a focus on shareReplay and effective data caching strategies. It showcases common pitfalls and best practices when caching HTTP requests.
- Simple approach using a
nullvariable check - Problems:
- Subscription leaks (no unsubscribe)
- Incorrect API response handling
- Race conditions on multiple calls
- Refresh button doesn't work once cached
- Uses RxJS
shareReplay(1)operator for automatic caching - Benefits:
- No subscription leaks
- Prevents duplicate HTTP requests
- Shares single subscription among multiple subscribers
- Caveat:
- Can cache errors permanently (solved with
retry+catchError)
- Can cache errors permanently (solved with
- Most sophisticated approach using
BehaviorSubjectas a refresh trigger - Benefits:
- Smart refresh without resetting cache
- Reactive pattern (RxJS idiomatic)
- Errors are not permanently cached
- All subscribers get updates simultaneously
- Use case: Production applications requiring reliable refresh capabilities
- Node.js (v16+)
- Angular CLI
# Navigate to project
cd angular-shareReplay
# Install dependencies
npm install# Start development server
ng serve
# Navigate to browser
http://localhost:4200The application displays Star Wars vehicles fetched from an external API. You can test three different caching approaches:
- Basic Caching - Click "Load Vehicles (Basic)" to test simple manual caching
- ShareReplay - Click "Load Vehicles (ShareReplay)" to test shareReplay caching with retry
- BehaviorSubject - Click "Load Vehicles (Behavior)" to load, then "Refresh Data (Behavior)" to trigger refresh
- app.service.ts - Service with three caching implementations
- app.ts - Component demonstrating all three methods
- app.html - UI with buttons to test each approach
// ❌ Wrong - Creates new observable every call
return this.http.get(...).pipe(shareReplay(1)); // shareReplay ineffective
// ✅ Correct - Stores and reuses same observable
if (!this.cached$) {
this.cached$ = this.http.get(...).pipe(shareReplay(1));
}
return this.cached$;// Use retry() before catchError() and before shareReplay()
this.http.get(...)
.pipe(
retry(2),
catchError(error => {
this.cache$ = null; // Reset on error
return throwError(() => error);
}),
shareReplay(1)
)// BehaviorSubject triggers fresh requests
private refreshTrigger$ = new BehaviorSubject<void>(undefined);
this.refreshTrigger$.pipe(
switchMap(() => this.http.get(...)),
shareReplay(1)
)- First call - Makes HTTP request
- Second call - Uses cached data (no new request)
- Refresh button - Triggers new HTTP request
- Check Network tab - See which pattern makes new requests