JavaScript中的函数响应式编程是否会导致侦听器引用的问题更大?

18

在JavaScript中,观察者模式经常被使用。其中有一个棘手的问题是主题(subject)对观察者(observers)的引用。它们需要清理。对于常规应用程序,我使用以下经验法则:

  • 如果主题的生命周期短于(或等于)观察者,则可以直接执行subject.on('event', ...)
  • 如果主题的生命周期长于观察者,则需要使用observer.listenTo(subject, 'event', ...)

在第二种情况下,listenTo了解观察者的生命周期,并且它会在观察者结束时自动删除侦听器。

在现代SPA(单页应用程序)样式中,任何时候只有应用程序的某些部分处于活动状态,这变得非常重要。如果将其与Web套接字配合使用,这是事件流的完美候选者,而且很可能具有长生命周期,那么这就更加重要了。

使用FRP时,例如代表随时间变化的值的事件流,我(不知道)创建了许多侦听器。每个filtermapflatMap都会创建一个新流,该流可能使用侦听器与上一个流相连接。

在我的脑海中,确定何时以及如何删除这些侦听器似乎非常棘手。我想象不到自己是第一个思考这个问题的人,但我在互联网上找不到太多相关信息。

我看到其他语言的一些框架使用弱引用(weak references)。JavaScript没有弱引用(WeakMap在此处无法使用)的概念。即使有了它,似乎也不是一个好主意,因为垃圾回收的时间不清楚。

  • 当前框架是如何解决这个问题的?
  • 框架是否与对象的生命周期联系在一起?如果是:如何实现?

1
如果你认为这个问题应该被关闭,请添加评论。也许提出一个建议让这个问题更加具体化。或者在适合的地方指向一个更好的答案。如果不清楚,请提问。我真的想使用FRP。 - EECOLOR
抱歉,我不得不投票关闭。这个问题太过开放了。 - JK.
@JK,你有关于改进问题的建议吗? - EECOLOR
我错了,已经有一个人回答了,他对所有三个方面都足够了解。 - Apanatshka
@Apanatshka,我仍然认为你的评论是有价值的。在下一个问题中,我会尽量考虑到它。 - EECOLOR
显示剩余2条评论
1个回答

12
在 RxJs 中,每个 Observer 默认情况下都会在原始事件源上拥有一个独立的监听器。因此,如果您有多个观察者,每个观察者都将消耗额外的内存和处理能力。
var s = $('#textInput').keyupAsObservable()
s.subscribe(subscriber1);
s.map(function() {}).subscribe(subscriber2);

你将有两个 keyup 监听器。你可以使用 .publish().refCount() 来使 Observable 维持与源的单一连接。

在 Bacon.js 中,Observables 总是维持与它们的源的单一连接。

在这两个库中,与源的连接是惰性创建的(添加 Observer 时),并且在(最后一个)Observer 被移除时自动移除。因此,你不必手动管理监听器。

但是,在 subject 的生命周期比 Observer 更长的情况下,你必须确保观察者在其生命周期结束时停止订阅,否则就会有泄漏。这两个库都没有任何“神奇”的方式来管理这个问题,因为对于库来说,你的 Observer 只是一个函数。

个人而言,我经常创建一个名为 deathObservable 或其他东西,以信号观察者的生命周期结束,然后我订阅 subject.takeUntil(death) 而不是直接订阅 subject

关于 Elm,我的理解是你一次设置了整个事件网络,因此没有泄漏的可能性;Observers 无法在以后添加。


你对Elm的理解是正确的,所以在最后的陈述中可以更加自信。这种语言只允许静态事件网络(在Elm中称为信号图),因此代码可以(并且已经)编译成JavaScript,在初始化时构建完整的网络,并且不需要处理订阅/取消订阅。 - Apanatshka
“死亡”这个概念是一个有趣的概念。很高兴知道你提到的框架中没有任何东西可以帮助处理生命周期。 - EECOLOR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接