Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does toPromise() unsubscribe from the Observable?

Tags:

rxjs

I have not been able to find any normative text to answer this question. I have been using this code pattern (this is in TypeScript in an Angular application):


observeSomethingFun$: Observable<Fun>;
    ...
async loadsOfFun() {
  const fun = await this.observeSomethingFun$.toPromise();
    // I now have fun
}

In general, Observables need to be unsubscribed from. This happens automatically when the Angular async pipe is used but what happens in this case? Does toPromise unsubscribe after emitting one value?

If not, how do I unsubscribe manually?

Update:

It turns out @Will Taylor's answer below is correct but my question needs some clarification.

In my case the Observable emits a never-ending stream, unlike for example Angular's HttpClient Observables that complete after emitting one value. So in my case I would never get past the await statement according to Taylor's answer.

RxJS makes this easy to fix. The correct statement turns out to be:

const fun = await this.observeSomethingFun$.pipe(first()).toPromise();

The RxJS first operator will receive the first value and unsubscribe from the source Observable. it will then send out that value to the toPromise operator and then complete.

like image 253
AlanObject Avatar asked Dec 19 '19 01:12

AlanObject


People also ask

Does toPromise subscribe?

The toPromise function lives on the prototype of Observable and is a util method that is used to convert an Observable into a Promise . Inside this function we subscribe to the Observable and resolve the Promise with the last emitted value - attention - when the Observable completes!

Does Observable complete unsubscribe?

If and when an observable completes, any subscription to it will automatically be unsubscribed. In many cases, an observable will never emit a completion event.

How do I cancel Observable subscription?

An Observable subscription has an unsubscribe() function to releases resources/memory or to cancel the observable execution. In the above example we have multiple subscription(). We have stored them in a subscription() array and we have unsubscribe() them one by one in ngOndestroy() as shown in the above example.

What does toPromise return?

⚠ toPromise is not a pipable operator, as it does not return an observable.


1 Answers

First of all, thank you for this question and answer, I wrongly assumed toPromise() knew what it was doing in all scenarios and would unsubscribe when that observable completes (even if it is an observable stream)

So I will just say that it doesn't hurt to pipe all of your observables before using .toPromise()

I just went through a big ordeal of stepping through our app for memory leaks and found the above answer by Will to be good. The elaboration on the actual question was exactly the same issue I was running into.

We are stepping through each observable in the app right now and we use either

pipe(take(1)) which is equivalent to pipe(first()).

or we use pipe(takeUntil(this.destroyed)) where this.destroyed.next(true) is called when we destroy our particular component or service.

We use take() to keep our verbiage consistent so we can search for take or takeUntil across various components.

Long story short, yeah you might take a very slight performance hit piping your observables at each instance, but I highly recommend doing so in order to prevent any unwanted app-wide memory leak hunts. Then maybe if you have the time you can step through each one and see where .toPromise() actually unsubscribes correctly for you.

like image 107
Willie Avatar answered Sep 20 '22 02:09

Willie