I'm using rxjs 5.5.6.
I've created this code in order to show the behavior:
Observable.of(1, 2)
.do(a => {
console.log(a);
let d:string = null;
let r = d.length; // it raises an null exception
})
.catch(() => {
console.log("error catched"); //exception is capture here
return Observable.never();
})
.subscribe();
I was expecting that the output is:
1
error catched
2
error catched
However, the output is:
1
error catched
It means, the subscription terminates despite of an Observable.never()
is returned on .catch(...)
method chain.
Any ideas?
REAL CASE
this.subs = Observable
.merge(this.$searchQuery, this.$lazyQuery)
.do(() => this.loadingPage())
.map(filter => this.buildURL(user, app, filter))
.switchMap(url => this.service.getItemsFromService(url))
.map(response => this.buildPage(response))
.do(page => this.loadedPage(page))
.catch(() => {
this.loadedPage(pojo.Page.EMPTY);
return Observable.never();
})
.takeUntil(this.$unsubscribe)
.subscribe();
You get the output
1
error catched
because the first value throws an error in tap
which is propagated through the onError
channel which halts the sequence. With catch
you catch this error and move on to the next sequence (never
), but the first sequence (of(1,2)
) is still halted. So after 1
throws an error 2
is never processed by tap
.
After you return never
in catch
no value is emitted and the Observable never completes. If you add logs inside subscribe
for the next
, error
and complete
callbacks you will see that they are never executed.
Yes all the explanation by @frido is correct. With that answer I would like to add:
If you want to capture any error occuring in any particular Observable itself(say an HTTP request) then you need to handle it in that particular erroring Observable.
let correct = Observable.of("correct")
let inCorrect = Observable.throw('inCorect')
let obs = [inCorrect, correct];
let handledObs = obs.map(eachObs => {
return eachObs.catch((e) => {
console.log("Individual handler, Good Catch!");
return Observable.of("I am tampered");
})
})
forkJoin(...handledObs)
.do(a => {
console.log(a);
})
.catch(() => {
console.log("error catched");
return Observable.never();
})
.subscribe(data => {
console.log(`data`, data)
},(e) => {
console.log(`error`, e)
});
}
See an example here: https://stackblitz.com/edit/angular-7mmhn7?file=src/app/app.component.ts
EDIT
However when I look at your code, it looks to me that you are trying to log something and the returned data may not have a length
property, even in that case you want to proceed with the stream. If this is true then you can add a simple try
catch
under do()
from([1, 2])
.do(a => {
try {
console.log(a);
let d:string = null;
let r = d.length;
} catch(e) {
console.log(`catched under do`, e)
}
})
.catch(() => {
console.log("error catched");
return Observable.of('catched');
})
.subscribe(data => {
console.log(`data`, data)
},(e) => {
console.log(`error`, e)
});
Here is an example: https://stackblitz.com/edit/angular-bcrava?file=src/app/app.component.ts