4

I am building a website with Angular2 that consists of multiple pages containing a dashboard with various statistics.

On a single page, 6 different requests are made separately (one for each dashboard tile), which can take up to 5 seconds to conclude. The problem appears when I change the page whilst the requests for the dashboard are ongoing.

On this situation, the requests will start to stack up, and if I change the page multiple times the dashboards will take more and more time to be loaded. Each request is made the following way:

return this.http.post("http://mywebsite.com/dashboard/info", body, options)
    .map((res) => {
        return res.json()
    }).subscribe((result) => { /* do something */});

What I am looking for is for a way to abort all of the ongoing requests when I change the page, to avoid that they stack up and cause excessive loading times.

Manuel Reis
  • 574
  • 8
  • 29

2 Answers2

5

When you call subscribe an Subscription object is created and it persists until the observable is completed.

You have to unsubscribe from the post request when you no longer need the result. The most common way is to call unsubscribe from ngOnDestroy of a component.

/**
 * Disposes the resources held by the subscription. May, for instance, cancel
 * an ongoing Observable execution or cancel any other type of work that
 * started when the Subscription was created.
 * @return {void}
 */
unsubscribe(): void;

EDIT:

Note that is you call share(), take(), first() or any other operator that creates a new observable than unsubscribing will not cancel the HTTP request. As you'll be unsubscribing from a child observable only.

Reactgular
  • 52,335
  • 19
  • 158
  • 208
  • Just to make sure, calling any of the methods above will create a new observable, which unsubscribing will not cancel the HTTP request, is that correct? – Manuel Reis Jul 14 '17 at 13:46
  • @ManuelReis did this help you? Because the way I understood your question, you don't seem to actually be destroying the component (ngOnDestroy wouldn't be called). – AArias Jul 14 '17 at 13:50
  • @AArias I thought that too (and ngOnDestroy was not being imported on my component), but apparently on changing pages ngOnDestroy is called. I am now validating if this approach works – Manuel Reis Jul 14 '17 at 13:54
  • As long as the component does not actually disappear from the DOM, ngOnDestroy isn't being called. Let me know if that's the case to provide an actual solution. – AArias Jul 14 '17 at 13:57
  • 1
    The page is not refreshed, but the component is replaced by another one (e.g. dashboard1 -> dashboard2), so ngOnDestroy is being called. This solves my issue – Manuel Reis Jul 14 '17 at 14:03
  • @ManuelReis if you run into the case where a component is not destroyed between route changes. You can inject `ActivatedRoute` into any component and subscribe to one of the observables to watch for route changes. If your component is higher in the DOM then the route-outlet being used. You can inject `Router` and watch for all route changes. – Reactgular Jul 14 '17 at 14:38
  • @ManuelReis if you call `take()` or `first()` those operators do not emit data until the parent observable is completed, but they might unsubscribe if all subscribers also unsubscribe. Either way, you still have unsubscribe. – Reactgular Jul 14 '17 at 14:41
  • Sorry, not completed. I mean until they get their data. You have to read the manual on those. I get lost with all these operators. – Reactgular Jul 14 '17 at 14:42
2

you want to unsubscribe to your observable subscriptions. The subscription is returned when you subscribe to an observable (in this case this.http.post()). Then in the OnDestroy method of your page, you can unsubscribe to subscription which cancels the ongoing http request.

// subscription
this.subscription = this.http.post("http://mywebsite.com/dashboard/info", body, options)
    .map((res) => {
        return res.json()
    }).subscribe((result) => { /* do something */});

// within the ngOnDestroy of your component
onDestroy(){
    this.subscription.unsubscribe();
}
LLai
  • 13,128
  • 3
  • 41
  • 45