javascript - 当已订阅的主题完成时取消订阅
我有一个主题,它订阅了一个事件监听器 Observable(fromEvent)。当点击停止按钮时,主题完成,事件监听器应被移除。目前,我正在跟踪订阅并取消订阅,这也会移除事件监听器:
const { fromEvent, Subject } = rxjs
const { map } = rxjs.operators
const subject = new Subject()
subject.subscribe(() => console.log('focused'))
const sub = fromEvent(document.querySelector('input'), 'focus').subscribe(subject)
document.querySelector('button').onclick = () => {
// This is what I would like to avoid
sub.unsubscribe;
subject.complete();
}<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>
<input>
<button>Stop</button>是否有可能在 subject 完成时自动取消订阅 sub(并移除事件监听器)?类似于 takeUntilComplete(subject),而不安装额外的库。
编辑:这里的例子过于简单化。在我的实际情况中,没有按钮让受试者完成。
答案#1
你有点想太多了,这就是你所需要的全部:
const stop$ = fromEvent(document.querySelector('button'), 'click');
fromEvent(document.querySelector('input'), 'focus').pipe(takeUntil(stop$)).subscribe(subject)
takeUntil 的完成事件将向订阅的主题传播。所有订阅和事件监听器将在按钮点击时结束。
唯一不会发生的情况是,如果主题以除按钮点击以外的方式完成,那么您的输入事件仍然会触发,尽管订阅者不再监听。完成会向下游传播,但不会向上游传播。
或者,创建新的操作符相当容易(基于你的解决方案进行改编):
const takeUntilComplete = (subject) =>
takeUntil(new Observable(o =>
subject.subscribe(null, null, () => o.next())))
可以像这样简单使用:
fromEvent(document.querySelector('input'), 'focus').pipe(takeUntilComplete(subject)).subscribe(subject)
答案#2
不是很优雅,但创建一个在 subject 完成时发出值的新 Observable 是可行的:
fromEvent(...).pipe(
takeUntil(
new Observable((subscriber) =>
this._trackedInteractions$?.subscribe({ complete: () => subscriber.next() })
)
)
).subscribe(subject)
