3

I wonder if I am using Observable.subscribe() too many times or not.

In my component class, I have a function loadData(). It calls another function this.service.getData() that uses HttpClient.get() to perform a HTTP request to the server.

Currently in my function loadData(), I subscribe to the result of this.service.getData().

Each time the user clicks on a "Update" button, I would like to call my function loadData().

The question

  • If I call my function loadData() every time I need to perform HTTP request, will I create as many subscribers?
  • Is there a risk of memory leaks?
  • If so, do you know how I should refactor my code?

The answer

Samples of code

private loadData() {
    this.loading = true;
     const subscription = this.service.getData()
      .pipe(
  // console.log() with a delay added for test - START
  map(val => {
    window.setTimeout(() => {
      // This will print true.
      console.log('After delay: Is Subscriber closed?', subscription.closed);
    }, 10);
    return val;
  }),
    // console.log() with a delay added for test - END
    takeUntil(this.ngUnsubscribe))
      .subscribe(data => {
        this.data = data;
        // This will print false.
        console.log('Is Subscriber closed?', subscription.closed);
      },
      error => {
        console.error(error);
        throw error;
      },
      () => {
        this.loading = false;
      });
}
getData(): Observable<DataObject> {
    const uri = encodeURI(this.configService.getUri());
    const headers = new HttpHeaders();
    if (this.pipelineEtag) {
      headers.set('If-None-Match', this.pipelineEtag);
    }
    return this.http.get(uri, {
      headers: headers,
      observe: 'response'
    }).pipe(
      map(resp => this.processResponse(resp)),
      catchError(error => this.handleError(error, this.envProduction))
    );
}
Kris
  • 401
  • 2
  • 7
  • 16
  • I believe that http calls create cold observables, which means they indeed create a new subscription for each new value emitted. What you could do is store the subscription `this.x = this.myService.getData().subscribe(...)` and un subscribe manually, or implement a cache system for your requests. –  Sep 07 '18 at 13:42

3 Answers3

1

each time the HTTP Call returns a value, the Observable completes. so it is safe to do something like this in the Service

loadData() { 

    return this.http.get<Data>(dataUrl).pipe(
      //  tap(data => console.log(data)), // eyeball results in the console
      catchError(err => this.handleError(err))
    );

}

and then call

this.service.loadData().subscribe((data:Data) => do somthing)

you can even call exhaustMap or switchMap to control the Observable flow, in order to don't "hint" too many time the server

ALGDB
  • 650
  • 1
  • 6
  • 22
  • Yes thanks for your message. I didn't know about tap. I edited my code to show how I test that subscriber was closed. – Kris Sep 07 '18 at 15:49
  • Actually me too doing the similar subscribes multiple times in various components on a centralized data services (data services gets a http data). In my case, i am hitting json-server DB to get the JSON data via httpclient. What i have noticed is that, whenever subscribe is called either by async pipes or via component code, the json-service db is hit. I can see the json-server terminal updating itself upon every hit. So problem right? – Zenwalker Nov 29 '18 at 16:53
0

This is the correct usage, and there is no risk in creating multiple subscribers.

From the documentation:

The AsyncPipe subscribes (and unsubscribes) for you automatically.

Source


The technical detail is that once the Http request is completed, the observable's .complete method is called which kills all current subscribers. This means that your subscribers are created, used, and the immediately discarded.

Vlad274
  • 6,514
  • 2
  • 32
  • 44
  • Thanks for your comment. So I edited my post because I found on another post that actually Angular make observables automatically complete when making HTTP requests. I read on this page https://angular.io/tutorial/toh-pt6#chaining-rxjs-operators that the added value AsyncPipe is rather to not have to user subscribe() because done automatically – Kris Sep 07 '18 at 15:48
  • Actually me too doing the similar subscribes multiple times in various components on a centralized data services (data services gets a http data). In my case, i am hitting json-server DB to get the JSON data via httpclient. What i have noticed is that, whenever subscribe is called either by async pipes or via component code, the json-service db is hit. I can see the json-server terminal updating itself upon every hit. So problem right? – Zenwalker Nov 29 '18 at 16:54
0

So in the end

Kris
  • 401
  • 2
  • 7
  • 16