Lessons35. catchError inside switchMap
Lessons · 35
35. catchError inside switchMap
Where you put catchError is critical
From the previous lesson you know an error travels up the pipe until it meets a catchError. But there's a subtlety that's very important to grasp for real apps:
Once an error is caught, the stream completes at that point. An outer source below the catch keeps living. An outer source above the catch is dead too.
Two options
// BAD: catchError on the outside — kills the search field
query$.pipe(
switchMap(q => fakeRequest(q)),
catchError(...) // after the first error, query$ is dead
)
// GOOD: catchError inside switchMap — only one request fails
query$.pipe(
switchMap(q => fakeRequest(q).pipe(
catchError(...) // caught here — the outer query$ stays alive
))
)
A real scenario
A live-search field: the user types an odd query and the server returns an error. With catchError on the outside, the next keystroke won't work — the stream is dead. With it inside, only one request failed, and the next keystroke fires switchMap again.
Your task
- Inside the function passed to
switchMap, infakeRequest(query).pipe(...), addcatchError(error => of('Fallback: ' + query)). - Notice:
catchErrorsits in the inner pipe, not the outer one. - Expected output:
Result: ok → Fallback: bad → Result: next. Afterbadfails, the stream is alive and handlesnext.
Solution spoiler · click to reveal
const { from, of, throwError, switchMap, catchError } = Rx;
function fakeRequest(query) {
if (query === 'bad') {
return throwError(() => 'Request failed');
}
return of('Result: ' + query);
}
const query$ = from(['ok', 'bad', 'next']);
const result$ = query$.pipe(
switchMap(query => {
return fakeRequest(query).pipe(
catchError(error => of('Fallback: ' + query))
);
})
);
result$.subscribe(value => console.log(value)); script.ts
CONSOLE · Console output
Hit Run to see the result...