Reputation: 185
I'm having trouble understanding why unsubscribing from a rxjs subscription with an added step does not cancel a in-flight http request.
Take a look at: https://stackblitz.com/edit/angular5-http-example-nx8fza
You'll notice in the network tab for chrome, one of the clicks cancels requests and the other does not.
getJoke(): void {
this.jokeSub = this.api.getData()
.subscribe(data => this.joke = data);
this.jokeSub.unsubscribe();
}
// This method does not cancel requests in flight because of the .add step.
getJoke2(): void {
this.jokeSub2 = this.api.getData()
.subscribe(data => this.joke = data).add(console.log("Added step"));
this.jokeSub2.unsubscribe();
}
Side Note: I came across this when I setting up an http interceptor in Angular 7 with rxjs 6. I couldn't cancel requests when my interceptor had any logic in the pipe. I think if can figure out why its not working here, I can answer my more specific question.
Upvotes: 1
Views: 843
Reputation: 5364
The .add
method adds teardown logic and returns a new subscription for that teardown logic. That new subscription is added as an inner subscription to the initial one. So these subscription have parent-child relations, and if you unsubscribe from parent — child is also disposed.
Though unsubscribing from children wont complete the parent.
Heres an explanation from the docs on add method
Returns the Subscription used or created to be added to the inner subscriptions list. This Subscription can be used with remove() to remove the passed teardown logic from the inner subscriptions list.
Heres a playground for that. Try commenting out some timeouts:
const { timer } = rxjs;
const { finalize, take } = rxjs.operators;
const startedAt = Date.now();
const a = timer(0, 300).pipe(
finalize(createTeardown('a')),
take(10)
)
.subscribe(console.log);
const b = a.add(createTeardown('b'));
const c = a.add(createTeardown('c'));
// Try commenting out some of these
setTimeout(()=>a.unsubscribe(), 1000);
setTimeout(()=>b.unsubscribe(), 1000);
setTimeout(()=>c.unsubscribe(), 1000);
function createTeardown(name) {
return () => console.log(name, Date.now() - startedAt);
}
<script src="https://unpkg.com/[email protected]/bundles/rxjs.umd.min.js"></script>
To fix your particular code example, you'll need to store original subscription separately:
getJoke2(): void {
this.jokeSub2 = this.api.getData()
.subscribe(data => this.joke = data); // parent subscription (a)
this.jokeSub2
.add(() => console.log('Child teardown logic')); // child subscription (b)
this.jokeSub2.unsubscribe();
}
NOTE: this basically duplicates AlesD's answer. Joining this into one answer for transparency
Hope this helps
Upvotes: 1
Reputation: 12052
As already the other answer explains this is how rxjs works I add also how you should change your code to make it work like the first sample.
getJoke2(): void {
this.jokeSub2 = this.api.getData()
.subscribe(data => this.joke = data);
this.jokeSub2.add(console.log("Added step"));
this.jokeSub2.unsubscribe();
}
Also a link to a fork of your StackBlitz where you can see it works.
Upvotes: 1