rxjs forkJoin does not call subscribe - rxjs

I have a set of RxJs Observable that uses forkJoin. The issue I have is that the forkJoin makes the calls but subscribe does not get calls.
However, if I use zip it works.
I have created an example in StackBlitz. Is this a bug or am I doing it all wrong?

forkJoin only runs once all inner observables have completed. In your example, the inner observables never complete. zip runs once everytime all observables fire in order. If you want something to run anytime any observable fires, use combineLatest

Related

rxjs switchMap and tap issue

I was playing around with the switchMap operator to clearly understand what was happening to a "switched" inner observable.
At first i thought that switchMap was only "unsubscribing" from the switched inner observable, but then i realize it was in fact "unsubscribing AND completing" the inner observable.
To confirm that i've written this small snippet:
https://codesandbox.io/s/relaxed-meninsky-c5jmw?fontsize=14
As you can see, the finalize() operator is correctly called when the subject emit for the second time, but:
why does the complete handler of the tap operator is not called ?
This somehow make feel only 80% happy with my understanding of this operator.
A related not on that:
I've read and watch numerous sources regarding switchMap, including:
This (great) ngconf sources: https://medium.com/#shairez/a-super-ninja-trick-to-learn-rxjss-switchmap-mergemap-concatmap-and-exhaustmap-forever-88e178a75f1b
The official rxjs doc: https://rxjs-dev.firebaseapp.com/api/operators/switchMap
And none of them clearly state if inner observable is unsubscribed or unsubcribed AND closed ( or at least i did not understand it :) )
I've watched the switchMap operator source code and there is no mention to takeXXX operator, how can he complete the inner operator without that ?
tl;dr
Do you confirm that switchMap complete inner observable when switching ?
Why does tap operator does not work as expected ?
If switchMap effectively complete inner observable how can he do that without using a takeXXX operator internally ?
I think you are confusing the difference between unsubscribe() and complete(). For a hot observable like a Subject you can "stop" it in a few ways. From the 'top->down' with complete() as you did in your example, or from the 'bottom->up' with unsubscribe().
switchMap() does exactly what it says, it switches from the primary observable to a secondary (or 'inner') observable. That is why when you complete() the outer observable, it has no effect on the inner one - the chain has been switched. To affect the chain (as opposed to just affecting the Subject which is the source observable), you need to get a reference to the Subscriber, and then call that Subscriber's unsubscribe() method.
To see this, I've forked your CodeSandbox and produced this new one
As you will see in that CodeSandbox I have added a few more lines to show what is going on:
Note the new tap() in the chain right above the switchMap - this will show what is going on directly from the Subject() before the chain is switched to a different Observable with the switchMap operator.
The Subscription for the chain is now being captured in the variable sub which can be unsubscribed later to affect the chain from the bottom->up.
Note that the s.complete() after 10 seconds is now reflected in the Subject, and note also how it doesn't affect the chain at all.
Now note that the new sub.unsubscribe() after 15 seconds indeed kills the chain.
uncomment the take(5) in the newT() method to see that indeed the tap's complete method will be called if the source above it actually completes (top->down).
finalize() catches the fact that an unsubscribe has happened (bottom->up), note that it occurs both when switchMap() does the automatic unsubscribe upwards when s.next() is called on the Subject source, as well as when unsubscribe() is called on the Subscription, which again causes a bottom->up termination. In no case is your complete() called in the original observer because the chain is never actually completed. You can complete the chain with a take(10) operator if you want, to see how that works as well.
Hopefully this helps clear up the confusion a little. :)

Do I have to unsubscribe from completed observable in rxjs?

If an observable completes, do I still have to unsubscribe / dispose (in RxJS) the observable to remove the Observer (prevent memory leaks) or is this handled internally by Rxjs once a onComplete or onError event occurs?
No, you don't need to unsubscribe from an observable you know has completed.
If you look at the source code of the RxJS toPromise() function, you'll see a subscribe, but no unsubscribe. That's because it is not necessary, you know the observable is completed.

forkjoin not wait for all observables complete when no value emit from each observable

I have several observables request.
Each observable request is recursive call and when there is no more data, it will call EMPTY.
for example:
request1 = recursive observable call
request2 = recursive observable call
request3 = recursive observable call
Then i use forJoin
forJoin(request, request2, request3).subscribe();
The forkJoin will callback with complete when anyone of them finish. It actually not wait for all observables complete.
I check the rxjs document, it mention
When all observables complete, emit the last emitted value from each.
As I don't care these observables return value, so it would not emit value to the forkJoin observer. Then i found that in this case if only one complete, forkJoin observer is notified with complete.
Is this the observable limitation that i do need to emit value to able to wait for all observables complete?
Thanks a lot.
It is by design.
Reference here:
forkJoin short circuits if one of the streams completes without emitting a value.
Since EMPTY just emits 'complete' and nothing else, forkJoin will complete right there.
Actually, the other non-empty observables inside forkJoin will still be subscribed, but since forkJoin may complete before them (depends on when did the EMPTY appear in forkJoin), you may not be able to handle them inside the forkJoin's complete function.

Alternatives to subscribe for cold observable

In combineLatest the method gets invoked only when we apply a ".subscribe()" to its end.
I wanted to know if there are other alternatives than adding subscribe to combineLatest method.

Rxjs: Observable.combineLatest vs Observable.forkJoin

I'm wondering what are the differences between Observable.combineLatest and Observable.forkJoin?
As far as I can see, the only difference is forkJoin expects the Observables to be completed, while combineLatest returns the latest values.
Not only does forkJoin require all input observables to be completed, but it also returns an observable that produces a single value that is an array of the last values produced by the input observables. In other words, it waits until the last input observable completes, and then produces a single value and completes.
In contrast, combineLatest returns an Observable that produces a new value every time the input observables do, once all input observables have produced at least one value. This means it could have infinite values and may not complete. It also means that the input observables don't have to complete before producing a value.
forkJoin - When all observables are completed, emit the last emitted value from each.
combineLatest - When any observable emits a value, emit the latest value from each.
Usage is pretty similar, but you shouldn't forget to unsubscribe from combineLatest unlike forkJoin.
combineLatest(...)
runs observables in parallel, emitting a value each time an observable emits a value after all observables have emitted at least one value.
forkJoin(...)
runs observables in parallel, and emits a single value once all observables have completed.
Consideration for error handling:
If any of the observables error out - with combineLatest it will emit up to the point the error is thrown. forkJoin will just give back an error if any of the observables error out.
Advanced note: CombineLatest doesn't just get a single value for each source and move onto the next. If you need to ensure you only get the 'next available item' for each source observable you can add .pipe(take(1)) to the source observable as you add it to the input array.
There is a situation in Angular which would explain it better. Assume there is a change detection in Angular component, so the latest value is changed. In the pipe and tap methods of combineLatest, the code will be triggered as well. If the latest value is changed N times by the change detection, then the tap methods is also triggered N times as well.

Resources