Why doesn't the RxJS 5 reference documentation describe a catch operator? - rxjs5

Several tutorials on RxJS 5 talk about a catch operator but I can't see any info in the reference documentation. Why not? Is it supported?

It's a bit further down in the documentation: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-catch
Rx.Observable.throw(new Error('pow'))
.catch(err => Rx.Observable.of('caught: ' + err.message))
.subscribe(console.log);

Related

RXJS Observables how to access multiple observable values from mergeMap

I have an rxjs function using several rxjs operators from which I need to ultimately return an observable. My challenge is detailed below in the sample code with details of what I am trying to do. How can I accomplish this? Do I need a rewrite? Without the change I'm trying to make to access the values from Observable3 everything works as needed. I've tried many things including using withLatestFrom to bring in observable three and also combineLatest but to no luck.
Observable3 = of({obs3Prop1: value1, obs3Prop2: value2})
this.Observable1
        .pipe(
            switchMap(param1) => {
                return this.getCount(param1);
            }), 
            mergeMap((param2: number) => 
                this.Observable2
                .pipe(
//inside this pipe, return another observable from here using some rxjs operators
//where I need access to param2
//but I also need access to the value from Observable3
                )
            ),
        )
It seems like you could use just forkJoin() assuming the all source Observables complete:
mergeMap((param2: number) =>
forkJoin([
Observable3,
this.Observable2,
]).pipe(
mergeMap(([o3params, o2params]) => this.makeCall(o3params.param1, o2params)),
)
),

Observable unsubscribe inside subscribe method

I have tried to unsubscribe within the subscribe method. It seems like it works, I haven't found an example on the internet that you can do it this way.
I know that there are many other possibilities to unsubscribe the method or to limit it with pipes. Please do not suggest any other solution, but answer why you shouldn't do that or is it a possible way ?
example:
let localSubscription = someObservable.subscribe(result => {
this.result = result;
if (localSubscription && someStatement) {
localSubscription.unsubscribe();
}
});
The problem
Sometimes the pattern you used above will work and sometimes it won't. Here are two examples, you can try to run them yourself. One will throw an error and the other will not.
const subscription = of(1,2,3,4,5).pipe(
tap(console.log)
).subscribe(v => {
if(v === 4) subscription.unsubscribe();
});
The output:
1
2
3
4
Error: Cannot access 'subscription' before initialization
Something similar:
const subscription = of(1,2,3,4,5).pipe(
tap(console.log),
delay(0)
).subscribe(v => {
if (v === 4) subscription.unsubscribe();
});
The output:
1
2
3
4
This time you don't get an error, but you also unsubscribed before the 5 was emitted from the source observable of(1,2,3,4,5)
Hidden Constraints
If you're familiar with Schedulers in RxJS, you might immediately be able to spot the extra hidden information that allows one example to work while the other doesn't.
delay (Even a delay of 0 milliseconds) returns an Observable that uses an asynchronous scheduler. This means, in effect, that the current block of code will finish execution before the delayed observable has a chance to emit.
This guarantees that in a single-threaded environment (like the Javascript runtime found in browsers currently) your subscription has been initialized.
The Solutions
1. Keep a fragile codebase
One possible solution is to just ignore common wisdom and continue to use this pattern for unsubscribing. To do so, you and anyone on your team that might use your code for reference or might someday need to maintain your code must take on the extra cognitive load of remembering which observable use the correct scheduler.
Changing how an observable transforms data in one part of your application may cause unexpected errors in every part of the application that relies on this data being supplied by an asynchronous scheduler.
For example: code that runs fine when querying a server may break when synchronously returned a cashed result. What seems like an optimization, now wreaks havoc in your codebase. When this sort of error appears, the source can be rather difficult to track down.
Finally, if ever browsers (or you're running code in Node.js) start to support multi-threaded environments, your code will either have to make do without that enhancement or be re-written.
2. Making "unsubscribe inside subscription callback" a safe pattern
Idiomatic RxJS code tries to be schedular agnostic wherever possible.
Here is how you might use the pattern above without worrying about which scheduler an observable is using. This is effectively scheduler agnostic, though it likely complicates a rather simple task much more than it needs to.
const stream = publish()(of(1,2,3,4,5));
const subscription = stream.pipe(
tap(console.log)
).subscribe(x => {
if(x === 4) subscription.unsubscribe();
});
stream.connect();
This lets you use a "unsubscribe inside a subscription" pattern safely. This will always work regardless of the scheduler and would continue to work if (for example) you put your code in a multi-threaded environment (The delay example above may break, but this will not).
3. RxJS Operators
The best solutions will be those that use operators that handle subscription/unsubscription on your behalf. They require no extra cognitive load in the best circumstances and manage to contain/manage errors relatively well (less spooky action at a distance) in the more exotic circumstances.
Most higher-order operators do this (concat, merge, concatMap, switchMap, mergeMap, ect). Other operators like take, takeUntil, takeWhile, ect let you use a more declarative style to manage subscriptions.
Where possible, these are preferable as they're all less likely to cause strange errors or confusion within a team that is using them.
The examples above re-written:
of(1,2,3,4,5).pipe(
tap(console.log)
first(v => v === 4)
).subscribe();
It's working method, but RxJS mainly recommend use async pipe in Angular. That's the perfect solution. In your example you assign result to the object property and that's not a good practice.
If you use your variable in the template, then just use async pipe. If you don't, just make it observable in that way:
private readonly result$ = someObservable.pipe(/...get exactly what you need here.../)
And then you can use your result$ in cases when you need it: in other observable or template.
Also you can use pipe(take(1)) or pipe(first()) for unsubscribing. There are also some other pipe methods allowing you unsubscribe without additional code.
There are various ways of unsubscribing data:
Method 1: Unsubscribe after subscription; (Not preferred)
let localSubscription = someObservable.subscribe(result => {
this.result = result;
}).unsubscribe();
---------------------
Method 2: If you want only first one or 2 values, use take operator or first operator
a) let localSubscription =
someObservable.pipe(take(1)).subscribe(result => {
this.result = result;
});
b) let localSubscription =
someObservable.pipe(first()).subscribe(result => {
this.result = result;
});
---------------------
Method 3: Use Subscription and unsubscribe in your ngOnDestroy();
let localSubscription =
someObservable.subscribe(result => {
this.result = result;
});
ngOnDestroy() { this.localSubscription.unsubscribe() }
----------------------
Method 4: Use Subject and takeUntil Operator and destroy in ngOnDestroy
let destroySubject: Subject<any> = new Subject();
let localSubscription =
someObservable.pipe(takeUntil(this.destroySubject)).subscribe(result => {
this.result = result;
});
ngOnDestroy() {
this.destroySubject.next();
this.destroySubject.complete();
}
I would personally prefer method 4, because you can use the same destroy subject for multiple subscriptions if you have in a single page.

deprecated concat operator in RxJS epic

I have an epic works well with concat operator. Webstorm starts saying it is deprecated in the way I use it. Says
deprecated export function concat<{type: string}[]>( v1: {type: string}[], scheduler: SchedulerLike): Observable>
Use scheduled and concatAll (e.g. scheduled([o1, o2, o3], scheduler).pipe(concatAll())
Can't figure out, how to rewrite this code?
const epic = action$ => action$.pipe(
ofType(TYPE),
mergeMap(() =>
concat(
of({type: 'START'}),
ajax.getJSON('someurl').pipe(
mergeMap(serverResponse => ([
{type: 'LOADED'},
{type: 'DO_JOB', serverResponse}
]))
)
)
)
Use concatWith. concatWith is actually not a completely new operator. It’s only meant to replace the concat operator which is currently marked as deprecated and will be removed in v8.
There’s one subtle difference between the two, though. concatWith only accepts inputs of type ObservableInput, whereas concat can also take a scheduler.
More details can be found here
It's not a deprecation in your case.
The deprecation affect only concat with scheduler parameter. (an other signature of the function). (See other similar issue: https://github.com/ReactiveX/rxjs/issues/4723)
You can use:
// tslint:disable-next-line:deprecation
concat(...);

Why is there no onComplete() rxjs operator?

Why rxjs contains no onComplete operator, i.e., one that allows to do something when the source observable completes? The finalize operator works for both completion and error, while I need to only react to completion.
Yes, I know that I can use the onComplete callback of the subscribe() function, but this is something completely different. Sometimes you only want to do certain stuff on completion inside the rxjs pipeline, and not inside the subscribe call.
Am I missing something?
The tap operator accepts three arguments (value, error, completion)
ons$.pipe(
tap(null, null, () => console.log("Done")),
).subscribe()
or alternatively an observer, so you can do this:
obs$.pipe(
tap({ complete: () => console.log("Done") })
).subscribe()
See the operator docs for more: https://rxjs-dev.firebaseapp.com/api/operators/tap
I would recommend the observer syntax as this is the syntax that has been recommended by Ben Lesh in the past since it's more expressive.

Side-effects only when using Pipeable Operators?

I'm rewriting some of my code to use Pipeable Operators in place of "patch" operators and I'm a little confused about when to use pipe() and how do I subscribe to a piped Observable to "activate" it if I only want side-effects?
For example, I have this code:
this.messages$ = this.messageService.getMessages(messageType)
.do((messages: Message[]) => {
console.log('The first message is ' + deviceMessages[0].text);
});
I get confused here because I figure I want to do this.messageService.getMessages(messageType).pipe(...) so I get an Observable returned and assigned to this.messages$ but then that won't execute because I haven't subscribe()'d. But if I do .pipe(...).subscribe() then it'll return a Subscription object, which isn't what I want.
What should I be doing here?
Well, do it simply like this:
this.messages$ = this.messageService.getMessages(messageType).pipe(
tap((messages: Message[]) => {
console.log('The first message is ' + deviceMessages[0].text);
})
);
this.messages$.subscribe();
the tap operator is the equivalent of .do() in rxjs 5 and above.

Resources