0

I've been facing a few alternatives in retrieving data from a simple API call when you will always get a single response, and I want to know what would be the best approach.

Initially I've used the plain subscribe, then I've learnt about memory leaks. Later I've used either _service.pipe(take(1)).subscribe or packages like untilDestroyed that cancel the subscription upon component destruction.

Assigning the subscription to a variable and unsubscribing on ngOnDestroy is the least desirable option for me.

Another option is converting the observable to a promise and then use a bit of syntactic sugar with async/await.

Since I am periodically refactoring my code, the question remains. What is the best approach and why?

Sen Alexandru
  • 1,953
  • 3
  • 19
  • 35
  • Go with the subscribption based method. This is how angular is build and you can leverage the RxJs benefits also. Regarding subscription handling you can use the async pipe in template to bind it with subscription and it will take care of all the issues like memory leak . – Vimal Patel Dec 04 '20 at 07:43
  • Use observables (avoid promises) and look into @ngrx/store and Redux. Once you make the change to redux, you won't look back. – Michael Kang Dec 04 '20 at 07:45
  • See [Is it necessary to unsubscribe from observables created by Http methods?](https://stackoverflow.com/questions/35042929/is-it-necessary-to-unsubscribe-from-observables-created-by-http-methods) regarding unsubscribing. Best practice is `takeUntil(this.destroy$)`. Using `toPromise` won't unsubscribe for you. – frido Dec 04 '20 at 10:38

1 Answers1

2

Using subscribe with http requests is totally fine and you should't worry so much about memory leaks because the stream completes right after the data from the server is passed trough it.

You should worry about the subscriptions on long-lived observables/subjects which don't complete automatically after the first value. In that case you can use operators or the subscription object in order to manage those subscriptions. Some useful operators are take(), first(), takeUntil(), takeWhile()

One approach that I like is to create an observable on my component and I often call it isAlive$ and inside the ngOnDestroy I emit a value from from this subject in order to cancel all my subscriptions.

class Cmp {
  isAlive$ = new Subject();
  
  ngOnInit() {
     this.someLongLivedObservable$.pipe(takeUntil(this.isAlive$)).subscribe(() => { 
        // do something 
    });
  }

  ngOnDestroy() {
    this.isAlive$.next();
    this.isAlive$.complete();
  }
}

Also you can connect subscriptions like:

const subscription1 = observable1.subscribe(val => console.log(val));
const subscription2 = observable2.subscribe(val => console.log(val));
subscription1.add(subscription2);

When we join subscriptions we can unsubscribe to all the subscriptions that were joined by calling unsubscribe on the first.

user1
  • 1,035
  • 1
  • 9
  • 17
  • thank you for your answer. can you share an example of simple request? Also, what do you do when you need to evaluate the returned data before executing the consecutive code? – Sen Alexandru Dec 04 '20 at 08:24
  • 1
    As mentioned http requests are as simple as doing `this.http.get('/something').subscribe()` and it will complete after the data is returned or if there is an error. If you want to do a consecutive request you can use `switchMap`. `this.http('/something').pipe(switchMap(data => zip([data], this.http('something-else')))).subscribe(([firstRequestData, secondRequestData]) => { console.log(firstRequestData, secondRequestData); })` Here I'm using zip in order to zip (create an array with the two values and pass it down the stream) those two values together. – user1 Dec 04 '20 at 08:29