问题归结为这一行:
subject.unsubscribe((v) => {
console.log(v);
});
Subject
实施ISubscription https://github.com/ReactiveX/rxjs/blob/5.4.2/src/Subject.ts#L22;这意味着它有一个unsubscribe
方法和一个closed
财产。它是实施unsubscribe https://github.com/ReactiveX/rxjs/blob/5.4.2/src/Subject.ts#L96-L100如下:
unsubscribe() {
this.isStopped = true;
this.closed = true;
this.observers = null;
}
这有点残酷。本质上,它会切断与该主题的任何订阅者的所有通信,而无需取消订阅。同样,它不会从它可能碰巧订阅的任何可观察对象中取消订阅主题本身。 (它还将主题标记为关闭/停止,这就是您错误的原因。)
鉴于它实际上并不执行任何取消订阅,因此尚不清楚它应该如何使用。的描述这次测试 https://github.com/ReactiveX/rxjs/blob/5.4.2/spec/Subject-spec.ts#L235-L276:
it('should disallow new subscriber once subject has been disposed', () => {
表明这可能是 RxJS 4 的某种后遗症 - 其中取消订阅被称为处置。
无论其存在的原因是什么,我建议永远不要调用它。举例来说,看看这个片段:
const source = Rx.Observable
.interval(200)
.take(5)
.do(value => console.log(`source: ${value}`));
const subject = new Rx.Subject();
source.subscribe(subject);
const subscription = subject
.switchMap(() => Rx.Observable
.interval(200)
.take(5)
.delay(500))
.subscribe(value => console.log(`subscription: ${value}`));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>
它将主题订阅到源可观察量,然后订阅由该主题组成的可观察量。
If unsubscribe
当这个主题被调用时,一些问题就变得明显了:
- 主题对源的订阅并未取消订阅,并且当源尝试调用主题的
next
方法;和
- 对由主题组成的可观察量的订阅不会取消订阅,因此
interval
内可观察到switchMap
后继续发光unsubscribe
已拨打电话。
试试看:
const source = Rx.Observable
.interval(200)
.take(5)
.do(value => console.log(`source: ${value}`));
const subject = new Rx.Subject();
source.subscribe(subject);
const subscription = subject
.switchMap(() => Rx.Observable
.interval(200)
.take(5)
.delay(500))
.subscribe(value => console.log(`subscription: ${value}`));
setTimeout(() => {
console.log("subject.unsubscribe()");
subject.unsubscribe();
}, 700);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>
这些似乎都不是理想的行为,所以打电话unsubscribe
on a Subject
是应该避免的事情。
相反,您的代码片段中的代码应该使用以下方式取消订阅Subscription
由返回subscribe
call:
const subscription = subject.subscribe((v) => {
console.log(v);
});
subscription.unsubscribe();
写完这个答案后,我发现了以下评论 https://medium.com/@benlesh/on-the-subject-of-subjects-in-rxjs-2b08b7198b93 from Ben Lesh http://stackoverflow.com/users/135786,这符合我的理论,即它与主题的处理有关:
如果你想让对象在你说话时大声而愤怒地犯错next
当它有用后,你可以调用unsubscribe
直接作用于主题实例本身。