Rxjs handle error in separate pipeline and merge - rxjs

I want to split Observable into two streams of Observable on error
catch operator can convert error into valid by returning an observable or propagate error either by throwing or returning Observable.throw
partition operator only processes valid values, no errors pass through this
what I need is split Observable into two Observables and process then differently and merge them as seen in below diagram

Pattern like this might fit your use case
step1
.map((data)=>{data:data})
.catch(()=>Observable.of({error:'error'})
.flatMap((res)=>{
//process A and B should return observable
if(res.data) return processA(res)
return processB(res)
})
.map(res=>{
//do your merged processing here
})
.subscribe()

Related

Should I use map or switchmap when using angular http module?

I use the following code in an angular app. I used the RxJS map call similar to how array map is used. After reading about RxJS switchmap operator, I'm not sure whether I should use map or switchmap. Should I use switchmap so the observable which is returned from the http call is closed so there is no memory leak?
getPeopleForTypeahead(term: string): Observable<IPersonForTypeahead[]> {
var peopleUrl = `https://localhost:5001/api/peoplesearch?name=${term}`;
return this.http.get<any>(peopleUrl)
.pipe(
map(pl => {
return this.peopleAsFlattened(pl.peopleList).reduce((p, c) => p.concat(c));
}),
catchError(this.handleError('getPeopleForTypeahead', []))
);
}
peopleAsFlattened = (pla: IPeopleList[]) => {
return pla.map(pl => pl.people.map(p => {
return {
id: p.id,
fullName: p.fullNames[0].firstName + " " + p.fullNames[0].lastName
};
}));
}
map and switchMap have completely different purposes:
map - transform the shape of an emission
switchMap - subscribe to an observable and emit its emissions into the stream
map
Use map when you want transform the shape of each emission. Ex: emit the user name property, instead of the entire user object:
userName$: Observable<string> = this.service.getUser(123).pipe(
map(user => user.name)
);
switchMap
Use switchMap when you want to map an emission to another observable and emit its emissions. Ex: You have an observable of some id and want to emit the resource after fetching it:
user$: Observable<User> = this.userId$.pipe(
switchMap(id => this.service.getUser(id)),
);
When user$ is subscribed to, the user returned from service.getUser(id) is emitted (not the userId string).
switchMap is not interchangeable with the map operator, nor vise versa. Although both of them has to do with mapping (as their names suggest), they have two separate use-cases.
In your particular case, the map operator is the way to go.
When to use switchMap?
You can only use switchMap(cb) when you check all these requirements:
Your callback function, cb, passed into switchMap returns an observable, observable$.
If your cb (callback function) does not return an observable, you should look into operators that don't handle higher-level observables, such as filter and map (what you actually needed); not operators that handle higher-level observables such as concatMap and well, switchMap.
You want to execute your cb sequentially before the next operation down the pipeline (after switchMap) executes.
Maybe you want to run logic inside of cb, and optionally get the return value of cb after executing, so that you can pass it down the pipeline for further processing, for example.
When you want to "discard" what will happen to cb's execution and re-execute cb every time the source observable (the thing that trickles down to switchMap(cb)) emits a new value/notification.
Applying what we hopefully learned, we know that your cb:
pl => {
return this.peopleAsFlattened(pl.peopleList).reduce((p, c) => p.concat(c));
}
returns a plain JavaScript array; not an observable. This takes using switchMap out of the question since it violates the first requirement I made up above.
Hopefully that makes sense. :)
We use switchMap when the source observable is a hot observable. In which case you prefer the behaviour that cancel the succeeding observable when source emits.
In your code, you source is a one-off http call which means it will not emit multiple times and the follow up action is not executing observable but to mutate an array. There is no need to use switchMap

In what cases take operator is actually used?

I would like to understand why take operator is used in code given below.
private _places = new BehaviorSubject<Place[]>(
// places for initialization
);
get places() {
return this._places.asObservable();
}
addPlace(title: string, description: string, price: number)
{
generatedId: string;
newPlace: Place;
// code to initialize newPlace
return this.http.post<{name: string}>(
'https://ionic-angular-ef2f8.firebaseio.com/offered-places.json',
{...newPlace, id: null})
.pipe(
switchMap(response => {
generatedId = response.name;
return this.places;
}),
take(1),
tap(places => {
newPlace.id = generatedId;
this._places.next(places.concat(newPlace));
})
);
}
post request returns an Observable, and we get a value from it in switchMap operator (note that we do not take a value before calling switchMap). In switchMap we replace the observable with a new observable got from _places, a BehaviourSubject object. After switchMap we use take operator.
Why don't we skip take operator, and use tap straight off? Do we take a value from an observable, because the observable is generated from a subject? Who can explain the use case of take operator in details?
UPDATE
I suspect that the reason I should use take operator after switchMap is that switchMap returns an observable received from an object of type BehaviorSubject which holds emitted values. One can subscribe to such BehaviorSubject object and take the latest emitted value - that's exactly what I did.
httpClient.post() emits one next notification and one complete notification.
However, they're using switchMap to merge another Observable to the chain (this.places). switchMap() won't complete until its source and the inner Observable complete so they're using take(1) to complete the chain after the first emission from this.places which is a BehaviorSubject that doesn't complete until you deliberately call complete() on it.
This is a very similar use-case to using takeUntil() to complete chains. takeUntil() always has to be the last operator in a chain because completing a source Observable to switchMap(), concatMap(), ... doesn't necessarily complete the whole chain. See this for more details https://medium.com/angular-in-depth/rxjs-avoiding-takeuntil-leaks-fb5182d047ef

Sequentially execute observables and emit one result

I have an array of observables which I'm executing in parallel using:
let observables: Observable<any>[]
Observable.forkJoin(observables)
This works perfectly, however, I need to execute the array of observables sequentially, and only emit one result if the last observable has been completed. That's when I tried to use
Observable.concat(observables)
But this returns multiple results, and not only one - combined - result which I get when using forkJoin. So I actually need a combination of the two.
I've tried to use the reduce functionality to execute them sequentially, like this:
return observables.reduce((previous, current) => {
return previous.flatMap(() => current);
}, Observable.empty());
But with this solution the observables are not executed at all.
Assuming that your observables emit singular values, not arrays, you could rework your current approach to something like:
return Observable.concat(...observables).reduce((acc, current) => [...acc, current], []);
or even shorter:
return Observable.concat(...observables).toArray();
In the case that they emit array values, you could do the following:
const source = Observable.concat(...observables).flatMap(list => list).toArray();
As Jota.Toledo or Mateusz Witkowski showed in their answers, with the new syntax of RxJS you can do:
return concat(...observables).pipe(toArray());
You can you use toArray() operator:
Observable.concat(observables).toArray().subscribe()
As stated in RxJS documentation: it creates "an observable sequence containing a single element with a list containing all the elements of the source sequence".

Is there an observable operator that is similar to forkJoin but only errors out if all of the request fails?

For example
return Observable.forkJoin([
getData1(),
getData2(),
getData3(),
getData4()
])
If one of them fails, the subscriber that subscribes to the forkJoin observable fails, is there an operator that only fails if all of them fails?
It's part of the design of rxjs that ANY error causes the chain of observables to fail.
It sounds like the condition you are trying to trap is not really a failure, but a normal case - if you change the sub-observables to detect the error and then return a value which can be detected down stream with something like a map or a filter, then you will be able to achieve what you are looking for.
if you're interested in getting error from inner observables, materialize might be way to go:
const pluckError = (obs: Observable<any>) =>
obs.materialize().filter(x => x.kind === 'E')
Observable.forkJoin(
obs1.pipe(pluckError),
obs2.pipe(pluckError)
....
)
It is important to note outer observable shouldn't raise error as it'll terminate whole observable, but you can catch / or get Notification metadata using materialize and only pick up error to make forkjoin completes.

RxJS5 Operator that can handle wrapped *and* unwrapped values?

With Promises, if you do this:
Promise.resolve(p).then(function(){
return 5;
})
.then(function(val){
return db.find(); // promise
});
we can see that then operator on promises can handle any returned value, it just calls Promise.resolve() on the return result and handles it whether it's a promise or not.
However, with RxJS5, I am finding it difficult to find an operator that can do something similar. I get a lot of errors:
TypeError: You provided x where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
at Object.subscribeToResult (/home/oleg/WebstormProjects/oresoftware/observable-persistent-queue/node_modules/rxjs/util/subscribeToResult.js:73:27)
at MergeAllSubscriber._next (/home/oleg/WebstormProjects/oresoftware/observable-persistent-queue/node_modules/rxjs/operator/mergeAll.js:85:42
for example, with this:
Rx.Observable.range(1,9)
.flatMap(function(){
return Rx.Observable.timer(4)
})
.concatAll() // this will throw the error
.subscribe();
is there an RxJS operator or pattern of operators that can handle any value and unwrap it like with Promises?
There is as far as my knowledge goes no operator which takes anything and just works. MergeMap/switchMap/concatMap will work with array/promises/observables as return values and convert them to Observable streams. But not with regular values.

Resources