-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Conversation
super(destination); | ||
constructor(public destination: Subscriber<T>, | ||
private notifier: Observable<any>) { | ||
super(null); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
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 . |
I tried to do that, but it's not the same case, and didn't work. skipUntil is a different beast than takeUntil. |
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. |
Yeah, that come to my mind as well. I'm going to try it now. |
@Blesh check if the latest commit does the trick. |
@staltz ... yeah. That's more in-line with what I was thinking. Perfect. Thanks, staltz. |
Can you, by chance, rebase this, @staltz? |
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.
3558a4f
to
7d869e9
Compare
Yep |
Resolves issue #577.