From a93518ae6a443211c4804dd2665bb04450d26614 Mon Sep 17 00:00:00 2001 From: John Cheevers Date: Fri, 10 Feb 2017 10:45:37 -0600 Subject: [PATCH 1/2] fix(switch): ChildSubscriptions removed on inner unsubscribe (#2355) Hold reference to ChildSubscription, not Subscription, so it can be properly removed later. --- src/operator/switch.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/operator/switch.ts b/src/operator/switch.ts index 8e5629fd86..ea936c5ab6 100644 --- a/src/operator/switch.ts +++ b/src/operator/switch.ts @@ -75,7 +75,7 @@ class SwitchSubscriber extends OuterSubscriber { protected _next(value: T): void { this.unsubscribeInner(); this.active++; - this.add(this.innerSubscription = subscribeToResult(this, value)); + this.innerSubscription = this.add(subscribeToResult(this, value)); } protected _complete(): void { @@ -90,7 +90,6 @@ class SwitchSubscriber extends OuterSubscriber { const innerSubscription = this.innerSubscription; if (innerSubscription) { innerSubscription.unsubscribe(); - this.remove(innerSubscription); } } From bb2f6b26f21094f9fb584c9a74df95e82cb02fcc Mon Sep 17 00:00:00 2001 From: John Cheevers Date: Fri, 10 Feb 2017 10:48:29 -0600 Subject: [PATCH 2/2] test(switch): should not leak ChildSubscriptions (#2355) --- spec/operators/switch-spec.ts | 42 ++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/spec/operators/switch-spec.ts b/spec/operators/switch-spec.ts index fd4135a2a0..71da684bde 100644 --- a/spec/operators/switch-spec.ts +++ b/spec/operators/switch-spec.ts @@ -223,4 +223,44 @@ describe('Observable.prototype.switch', () => { expect(completed).to.be.true; }); -}); \ No newline at end of file + + it('should not leak when child completes before each switch', () => { + let iStream: Rx.Subject; + const oStreamControl = new Rx.Subject(); + const oStream = oStreamControl.map(() => { + return (iStream = new Rx.Subject()); + }); + const switcher = oStream.switch(); + const result = []; + let sub = switcher.subscribe((x: number) => result.push(x)); + + [0, 1, 2, 3, 4].forEach((n) => { + oStreamControl.next(n); // creates inner + iStream.complete(); + }); + // Expect one child of switch(): The oStream + expect( + (sub)._subscriptions[0]._innerSub._subscriptions.length + ).to.equal(1); + sub.unsubscribe(); + }); + + it('should not leak if we switch before child completes', () => { + const oStreamControl = new Rx.Subject(); + const oStream = oStreamControl.map(() => { + return (new Rx.Subject()); + }); + const switcher = oStream.switch(); + const result = []; + let sub = switcher.subscribe((x: number) => result.push(x)); + + [0, 1, 2, 3, 4].forEach((n) => { + oStreamControl.next(n); // creates inner + }); + // Expect two children of switch(): The oStream and the first inner + expect( + (sub)._subscriptions[0]._innerSub._subscriptions.length + ).to.equal(2); + sub.unsubscribe(); + }); +});