RxJS: BehaviorSubject unsubscribe - javascript

I am very new to observables am worried about memory leaks. If I create the following:
private client = new BehaviorSubject("");
clientStream$ = this.client.asObservable();
and susbscirbe to them in views like so:
this.clientService.clientStream$.subscribe(
client => {
this.client = client;
}
}
do I need to unsubscribe? What if I called client.getValue()?

do I need to unsubscribe?
Probably.
If you're designing a subject which will complete -- ie, if you intend to callclient.complete() (or client.onCompleted() if you're using rxjs 4) -- then this will tear down the subscriptions automatically.
But often times, your behavior subject will be in some service which persists, and you don't want it to complete. In that case, you will need to unsubscribe. There are two ways you can unsubscribe:
1) Manually:
When you call .subscribe, you get back a subscription object. If you call .unsubscribe() on it (.dispose() in rxjs 4), you will unsubscribe. For example:
const subscription = this.clientService.clientStream$
.subscribe(client => this.client = client);
setTimeout(() => subscription.unsubscribe(), 10000); // unsubscribe after 10 seconds
2) Automatically, based on another observable. If you're using observables often in your application, you will probably find this approach to be very convenient.
Observables have a .takeUntil operator, which you can pass in another observable to. When that second observable emits a value, it will do the unsubscription for you. This lets you describe up front what conditions should tear down your observable. For example:
this.clientService.clientStream$
.takeUntil(Observable.timer(10000))
.subscribe(client => this.client = client);
What if I called client.getValue()
That will synchronously give you the current value. You're not subscribing at all. On the up side, this means you won't need to unsubscribe. But on the downside, why are you using a behavior subject if you're not interested in seeing when the value changes?

Related

Does overriding a Subscription automatically unsubscribes the previous value?

I have the following subscription in an angular application:
private _sub: Subscription;
On initialization I subscribe to a firebase get function:
this._sub = this.service.get('database1').subscribe(
data => {
this.ListOfData = data;
}
);
But depending on user input I change database1 to other collections, or use a different method instead of get().
When I override _sub will the previous stream get automatically unsubcribed, or do I have to manually do it before overriding?
Short answer: No it doesn't...I'll share the details on why
Whenever .subscribe() is called, a new instance of a Subscription is created that holds resources that listen to the execution of the Observable. If you call .subscribe() and do not call .unsubscribe(), your Subscription is still utilizing resources. In some cases (depending on the logic associated to the Observable/Subject) it can result in unexpected behavior in your application and it can impact performance. This is why the best practice is to call .unsubscribe() on your Subscription when you are done with it.
There are also functions called RxJS operators that can help you to manage your subscriptions by automatically unsubscribing based on certain criteria.
No, you have to unsubscribe. Sometimes they stay like sleeper cells to damage your application performance. Best practice is unsubscribe.

Purpose of "completing" an rxjs Subject?

What is the purpose of calling complete() on rxjs Subject?
As an example:
Calling complete on takeUntil() notifier Observable. Why do we need to do that, and not just call next() and be done with it?
P.S. If it's just a convention, why is it so?
complete is normally called on subjects in order to send the completed event through the stream. This is done in order to trigger observers that wait for that notification. For example:
var subject = new BehaviorSubject<int>(2);
var subjectStream$ = subject.asObservable();
var finalize$ = subjectStream$.pipe(finalize(()=> console.log("Stream completed")));
var fork$ = forkJoin(subjectStream$,of(1));
....
finalize$.subscribe(value => console.log({value}));
//output: 2, notice that "Stream completed" is not logged.
fork$.subcribe(values => console.log({values});
// no output, as one of the inner forked streams never completes
Furthermore, is a security measure in order avoid mem. leaks, as calling complete on the source stream will remove the references to all the subscribed observers, allowing the garbage collector to eventually dispose any non unsubscribed Subscription instance.

Why would I use RxJS interval() or timer() polling instead of window.setInterval()?

Use case: Call a function every minute (60000 ms) that dispatches store action to fetch lastUpdated status of items, which upon response and filtering, updates the store, and updated store is read as an observable and displayed in the view). This needs to happen for as long as the web app is open (so indefinitely).
Currently, I'm using this:
this.refreshDate = window.setInterval(
() => this.store.dispatch(new FetchLastUpdate())
, 60000);
And when view is destroyed/dismounted, I delete the interval as so:
if (this.refreshDate) {
clearInterval(this.refreshDate);
}
Is this efficient/effective, or is it troublesome?
Why would I want to use an RxJS polling strategy like:
interval(60000)
.pipe(
startWith(0),
switchMap(() => this.store.dispatch(new FetchLastUpdate()))
);
Or
timer(0, 60000)
.pipe(
switchMap(() => this.store.dispatch(new FetchLastUpdate()))
);
TL;DR: window.setInterval() vs. RxJS timer()/interval()
Conclusion/answers (for ease of research):
There is great benefit to using RxJS functions to set an interval or perform polling, these benefits are explained in the selected answer but also in comments, but it is concluded (by discussions in the comments) that for the very simple requirement defined in the "Use case" section at the beginning of this post, it is unnecessary to use RxJS, and in fact if you are not using RxJS in any other part of your program, do not import it just for this, however in my case, I had already imported and used RxJS elsewhere.
Advantage of RxJS:
Laziness
You can create your Observables and until you call subscribe nothing is happening. Observable = pure function. This gives you more control, easier reasoning and allows for next point...
Composability
You can combine interval/timer with other operators creating custom logic very easily in unified way - for example you can map, repeat, retry, take... etc. see all operators
Error Handling
In case of an error you are responsible for calling clearTimeout/clearInterval - Observables are handling this for you. Resulting in cleaner code and fewer memory leak bugs.
Of course anything you do with Observables you can also do without Observables - but that's not the point. Observables are here to make your life easier.
Also note that interval/timer are not good observable factories for polling because they do not "wait" for your async action to finish (you can end up with multiple async calls running over each other). For that I tend to use defer and repeatWhen like this:
defer(() => doAsyncAction())
.pipe(
repeatWhen(notifications => notifications.pipe(delay(1234)))
);
window.setInterval doesn't care about your callbacks state, it'll execute at the given interval despite the status of the execution of the past callback, and the only way to make it stop and skip is clear the interval or reinitialize it.
On the other hand, RxJS Observable based solutions(interval, timer) allow you to pipe conditional operators (takeWhile, skipWhile for example) which allows you to add a stop or implement a stop-start logic by just flipping a boolean flag, instead of adding complicated logic of clearing the interval, and then recreating it.
And they are observables, you can listen to them all across the application, and attach any number of listeners to it.
Error Handling is better too, you subscribe to all successes, and handle everything in a catch callback.

RxJS Subscriber unsubscribe vs. complete

I was reading through the RxJS docs and want to make sure I'm understanding the difference between Subscriber.unsubscribe() and Subscriber.complete().
Let's say I have an observable with two subscribers, subscriber1 and subscriber2. If subscriber1 calls unsubscribe on their subscription, it will no longer receive notifications from the observable but subscriber2 will continue to receive them.
The docs for .complete():
The Observer callback to receive a valueless notification of type complete from the Observable. Notifies the Observer that the Observable has finished sending push-based notifications.
Does this mean that in the same scenario above, subscriber1 could call complete and it would end the observable and stop the stream for both subscriber1 and subscriber2?
Subscribers don't call complete(). You can call complete() on a Subject or more typically it's called for you "indirectly" using operators such as take(), takeWhile(), ...
For example:
const s = new Subject();
const subscriber1 = s.subscribe(...);
const subscriber2 = s.subscribe(...);
s.complete(); // both subscribers will receive the complete notification
// or with `take(1)` operator it'll call `complete()` for you
const subscriber1 = s.take(1).subscribe(...);
const subscriber2 = s.take(1).subscribe(...);
s.next(42); // both subscribers will receive the complete notification
Note that calling complete() on a Subject changes its inner state and there's no way to make it non-complete again while just unsubscribing a subscriber has no effect on the Subject.
A little similar question: Observable Finally on Subscribe
From my experience with the API, the idea is that: you don't call the Observable, the Observable calls you. You are able to trigger things if you create a Subject and next/complete the Subject though.
That's why you will see some examples that have a "private" Subject as a class member, but the publicly exposed item is an Observable. The expectation is that you will subscribe to the Observable and the top level class will dispatch values through the Subject with next() and error(). The only way to complete the Observable/Subject is to complete() the Subject.
Additionally, Subscriber does not have an unsubscribe() method, a Subscription does.

How can I complete Observable in RxJS

Let's say we have an Observable:
var observable = Rx.Observable
.fromEvent(document.getElementById('emitter'), 'click');
How can I make it Complete (what will trigger onComplete event for all subscribed Observers) ?
In this present form, you cannot. Your observable is derived from a source which does not complete so it cannot itself complete. What you can do is extend this source with a completing condition. This would work like :
var end$ = new Rx.Subject();
var observable = Rx.Observable
.fromEvent(document.getElementById('emitter'), 'click')
.takeUntil(end$);
When you want to end observable, you do end$.onNext("anything you want here");. That is in the case the ending event is generated by you. If this is another source generating that event (keypress, etc.) then you can directly put an observable derived from that source as an argument of takeUntil.
Documentation:
http://reactivex.io/documentation/operators/takeuntil.html
https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/takeuntil.md
What worked for me is using the take() operator. It will fire the complete callback after x number of events. So by passing 1, it will complete after the first event.
Typescript:
private preloadImage(url: string): Observable<Event> {
let img = new Image();
let imageSource = Observable.fromEvent(img, "load");
img.src = url;
return imageSource.take(1);
}
I think what you are looking for is the dispose() method.
from: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md#cold-vs-hot-observables
Notice that the subscribe method returns a Disposable, so that you can unsubscribe to a sequence and dispose of it easily. When you invoke the dispose method on the observable sequence, the observer will stop listening to the observable for data. Normally, you do not need to explicitly call dispose unless you need to unsubscribe early, or when the source observable sequence has a longer life span than the observer. Subscriptions in Rx are designed for fire-and-forget scenarios without the usage of a finalizer. Note that the default behavior of the Observable operators is to dispose of the subscription as soon as possible (i.e, when an onCompleted or onError messages is published). For example, the code will subscribe x to both sequences a and b. If a throws an error, x will immediately be unsubscribed from b.
I found an easier way to do this for my use case, If you want to do something when the observable is complete then you can use this:
const subscription$ = interval(1000).pipe(
finalize(() => console.log("Do Something")),
).subscribe();
The finalize is triggered on complete, when all subscriptions are unsubscribed etc.

Categories