Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

skipUntil: fixes and tests #586

Merged
merged 3 commits into from
Nov 3, 2015

Conversation

staltz
Copy link
Member

@staltz staltz commented Oct 23, 2015

Resolves issue #577.

super(destination);
constructor(public destination: Subscriber<T>,
private notifier: Observable<any>) {
super(null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the destination still be passed to the constructor?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I do that, how should I write this class to actually unsubscribe when unsubscribe() is called?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@staltz there's a bit of secret sauce in that constructor that is used for setting up the unsubscription chain. I'm having a hard time just from the code change discerning what moving away from super(destination) is fixing. Can you describe the issue in more detail?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

So, first of all I don't fully understand why some things were built as they are in Subscriber with regards to the shared subscriptions. Would be good if someone can clarify what was the intent.

If super(destination) is used, the secret sauce in the constructor will set this._subscription.
Later, in Subscriber.proto.unsubscribe() it does:

if (this._isUnsubscribed) {
  return;
} else if (this._subscription) {
  this._isUnsubscribed = true;
} else {
  super.unsubscribe();
}

this._isUnsubscribed is false, so we go to the second if check, and this._subscription is truthy, so we just end up setting this._isUnsubscribed to true, but not actually unsubscribing the current Subscriber from the Observable.

So this test would not pass:

  it('should skip all element and does not complete when another observable never completes', function () {
    var e1 =   hot( '--a--b--c--d--e--|');
    var e1subs =    '^                !'; // <== unsubscribe should happen, but never does!
    var skip = cold('-');
    var skipSubs =  '^                !';
    var expected =  '-';

    expectObservable(e1.skipUntil(skip)).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
    expectSubscriptions(skip.subscriptions).toBe(skipSubs);
  });

The inner subscription for the skip Observable is correctly unsubscribed when e1 completes, but the subscription to e1 is not unsubscribed when e1 completes. Because of how Subscriber.proto.unsubscribe() was coded as I explained above.

That's not the only test that fails, other 3 tests also fail in a similar way: the subscription to the source isn't unsubscribed when the source completes.

PS: you already merged some PRs where I used the same technique: https://github.com/ReactiveX/RxJS/pull/562/files#diff-0864900d001ae5c1b7070f19e5e13a2eR33.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you're saying. It makes me wonder what other operators may have this side-effect from the single composite subscription architecture. @trxcllnt, what do you think?

It seems to me like, at least for skipUntil we can assign the destination in the subscriber directly rather than going through the super call. (As is in this PR). It does concern me that this will somehow break the unsubscription chain in cases where there is more than one operator before skipUntil, though. I haven't put much thought into that.

@benlesh
Copy link
Member

benlesh commented Oct 27, 2015

I think I'm going to mark this one as blocked until we have a chance to investigate the possible ramifications of the change... also #587 .

@benlesh benlesh added blocked and removed blocked labels Oct 27, 2015
@benlesh
Copy link
Member

benlesh commented Oct 27, 2015

Okay, @staltz ... I think this is just waiting for the same treatment you gave takeUntil in #587

@staltz
Copy link
Member Author

staltz commented Oct 27, 2015

I think this is just waiting for the same treatment you gave takeUntil in #587

I tried to do that, but it's not the same case, and didn't work. skipUntil is a different beast than takeUntil.

@benlesh
Copy link
Member

benlesh commented Oct 27, 2015

Yeah, you're right. I don't have time to investigate right now, but I have concerns about how this change will affect the subscription chain. It might be that in skipUntil it will have to be wired up more manually or something.

@benlesh
Copy link
Member

benlesh commented Oct 28, 2015

@staltz @trxcllnt ... what do you think about leaving the super(destination) call in there, but overriding unsubscribe to behave slightly differently for this operator? I haven't investigated this, just sharing a thought.

@staltz
Copy link
Member Author

staltz commented Oct 29, 2015

Yeah, that come to my mind as well. I'm going to try it now.

@staltz
Copy link
Member Author

staltz commented Oct 29, 2015

@Blesh check if the latest commit does the trick.

@benlesh
Copy link
Member

benlesh commented Oct 29, 2015

@staltz ... yeah. That's more in-line with what I was thinking. Perfect. Thanks, staltz.

@benlesh
Copy link
Member

benlesh commented Oct 29, 2015

Can you, by chance, rebase this, @staltz?

Andre Medeiros and others added 3 commits October 30, 2015 13:23
Add tests to skipUntil that assert when its source and notifier get
subscribed and unsubscribed.
Fix operator skipUntil to automatically unsubscribe from its
source whenever it completes. This is to conform RxJS Next with RxJS 4.

Resolves issue ReactiveX#577.
Change SkipUntilSubscriber to give the destination subscriber to the
constructor in Subscriber. Adapt SkipUntilSubscriber to handle
unsubscription-on-complete correctly, by overriding unsubscribe().

Addresses ReactiveX#577.
@staltz staltz force-pushed the tests-unsubscribe-skipUntil branch from 3558a4f to 7d869e9 Compare October 30, 2015 11:31
@staltz
Copy link
Member Author

staltz commented Oct 30, 2015

Yep

@benlesh benlesh merged commit 7d869e9 into ReactiveX:master Nov 3, 2015
@staltz staltz deleted the tests-unsubscribe-skipUntil branch November 3, 2015 22:12
@lock lock bot locked as resolved and limited conversation to collaborators Jan 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants