我有一个主题可以订阅事件监听器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>
是否可以在sub
完成后自动取消订阅subject
(并删除事件侦听器)?诸如takeUntilComplete(subject)
之类的东西,而无需安装其他库。
编辑:此处的示例过于简化。在我的真实情况下,没有按钮可以使主体完成。
答案 0 :(得分:3)
您有点想这个,这就是您所需要的:
const stop$ = fromEvent(document.querySelector('button'), 'click');
fromEvent(document.querySelector('input'), 'focus').pipe(takeUntil(stop$)).subscribe(subject)
takeUntil
中的完成内容将向下传播到订阅的主题。所有订阅和事件监听器都将以单击按钮结束。
WONT发生的唯一事情是,如果主题完成了除按钮单击之外的其他方式,则输入事件仍将触发,尽管订阅者将不再收听。完成向下游传播,但不向上游传播。
创建新的运算符也很容易(简化您的解决方案):
const takeUntilComplete = (subject) =>
takeUntil(new Observable(o =>
subject.subscribe(null, null, () => o.next())))
可以简单地用作:
fromEvent(document.querySelector('input'), 'focus').pipe(takeUntilComplete(subject)).subscribe(subject)
答案 1 :(得分:2)
不是很优雅,但是创建了一个新的Observable,它在完成主题工作时发出:
fromEvent(...).pipe(
takeUntil(
new Observable((subscriber) =>
this._trackedInteractions$?.subscribe({ complete: () => subscriber.next() })
)
)
).subscribe(subject)
答案 2 :(得分:1)
考虑扩展Subject
类以通知其取消订阅/错误/完成,如下所示:
class NotifyStateSubject<T> extends Subject<T>{
public stopped = new Subject<void>();
private notify(): void {
this.stopped.next();
this.stopped.unsubscribe();
}
public error(err: any):void {
this.notify();
super.error(err)
}
public complete():void{
this.notify();
super.complete()
}
public unsubscribe():void {
this.notify();
super.unsubscribe();
}
}
然后按以下方式使用它:
fromEvent(...).pipe(takeUntil(subject.stopped$)).subscribe(subject)