Retry and Error Recovery
RxJS provides operators to handle errors and keep streams alive when sources fail transiently.
retry — Resubscribe on Error
import { retry } from 'rxjs/operators';
this.http.get<User[]>('/api/users').pipe(
retry(3) // Resubscribe up to 3 times on error
).subscribe();
retryWith — Custom Retry Strategy
import { retry, timer } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
this.http.get<User[]>('/api/users').pipe(
retry({
count: 3,
delay: (error, retryCount) => {
console.log(`Retry ${retryCount} after error:`, error.message);
return timer(1000 * retryCount); // Exponential backoff
},
})
).subscribe();
catchError — Recover with Fallback
import { catchError, of } from 'rxjs';
this.http.get<User[]>('/api/users').pipe(
catchError(error => {
console.error('Failed to load users:', error);
return of([]); // Return empty array as fallback
})
).subscribe(users => {
this.users = users;
});
catchError — Re-throw
import { catchError, throwError } from 'rxjs';
this.http.get<User[]>('/api/users').pipe(
catchError(error => {
return throwError(() => new Error('Custom error message'));
})
).subscribe();
Throttling and Debouncing
Throttling operators control the rate of emissions, preventing excessive work from noisy streams.
debounceTime — Wait for Silence
import { debounceTime } from 'rxjs/operators';
this.searchInput.valueChanges.pipe(
debounceTime(300) // Wait 300ms after last emission
).subscribe(query => {
this.search(query);
});
throttleTime — Limit Rate
import { throttleTime } from 'rxjs/operators';
this.scroll$.pipe(
throttleTime(200) // Emit at most once per 200ms
).subscribe(() => {
this.updateScrollPosition();
});
delay — Shift Emissions
import { delay } from 'rxjs/operators';
this.data$.pipe(
delay(1000) // Delay all emissions by 1 second
).subscribe();
Throttling Operator Comparison
| Operator | Behavior | Use When |
|---|---|---|
debounceTime |
Wait for silence | Search inputs |
throttleTime |
Limit rate | Scroll, resize events |
auditTime |
Emit last in window | Button clicks |
sampleTime |
Emit latest on interval | Polling |
delay |
Shift all emissions | Timed sequences |
Practical Example: Search with Debounce
@Component({
selector: 'app-search',
template: `
<input [formControl]="searchControl" placeholder="Search...">
<p *ngFor="let result of results">{{ result.name }}</p>
`,
})
export class SearchComponent implements OnInit {
searchControl = new FormControl('');
results: SearchResult[] = [];
ngOnInit(): void {
this.searchControl.valueChanges.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap(query => this.searchService.search(query)),
catchError(() => of([]))
).subscribe(results => {
this.results = results;
});
}
}
Exponential Backoff Pattern
this.http.get('/api/data').pipe(
retry({
count: 3,
delay: (error, retryCount) => timer(1000 * Math.pow(2, retryCount)),
// 2s, 4s, 8s
}),
catchError(() => of(fallbackData))
).subscribe();
Quiz
1. What does the retry operator do?
2. What does catchError do?
3. Which operator should you use for search input throttling?
Flashcards
Question
What does retry do?
Click to reveal answer
Answer
Resubscribes to the source on error. Gives transient failures a second chance.
Question
What does catchError do?
Click to reveal answer
Answer
Intercepts errors, allows fallback values or re-throwing.
Question
Which operator for search throttling?
Click to reveal answer
Answer
debounceTime — waits for silence before emitting.
Revision Notes
Key Takeaways
- 1. retry resubscribes on error
- 2. catchError intercepts and recovers from errors
- 3. debounceTime throttles noisy streams
- 4. Exponential backoff prevents thundering herd
Interview Tips
- • Explain retry vs catchError
- • Be ready to describe throttling operators
- • Mention exponential backoff for production resilience
Cheat Sheet
Error Handling and Retry Cheat Sheet
retry:
retry(3) // Resubscribe up to 3 times
catchError:
catchError(() => of(fallbackValue))
debounceTime:
debounceTime(300) // Wait 300ms after last emission
Exponential backoff:
retry({ count: 3, delay: (err, i) => timer(1000 * Math.pow(2, i)) })