18

在 JavaScript 中,观察者模式经常被使用。它有一个棘手的问题,那就是主题保留观察者的参考。他们需要清理。对于常规应用程序,我使用以下经验法则:

  • 如果对象的寿命短于(或等于)观察者,我可以这样做subject.on('event', ...)
  • 如果主题的寿命比观察者长,我需要使用observer.listenTo(subject, 'event', ...)

在第二种情况下,listenTo它知道观察者的生命周期,它会在观察者死亡时自动移除监听者。

在现代 SPA(单页应用程序)风格中,在任何时候只有部分应用程序处于活动状态,这变得非常重要。如果你将它与 Web 套接字结合起来,它是事件流的完美候选者,并且很可能长期存在,这变得更加重要。

使用 FRP,具有表示随时间变化的值的事件流之类的东西,我(不知道)创建了很多侦听器。每个filter,mapflatMap创建一个新的流,该流与前一个流绑定(可能使用侦听器)。

在我看来,确定如何以及何时需要删除这些侦听器似乎非常棘手。我无法想象我是第一个考虑这个问题的人,但我在互联网上找不到太多关于这个问题的信息。

我见过一些其他语言的框架使用弱引用。JavaScript 没有弱引用的概念(WeakMap 在这里不可用)。即使有,这似乎也是一个坏主意,因为不清楚何时进行垃圾收集。

  • 这在当前框架中是如何解决的?
  • 框架是否与对象的生命周期相关联?如果是:如何?
4

1 回答 1

12

在 RxJs 中,Observer默认情况下,每个在原始事件源上都有一个单独的侦听器。所以,如果你有

var s = $('#textInput').keyupAsObservable()
s.subscribe(subscriber1);
s.map(function() {}).subscribe(subscriber2);

您将有两个 keyup 侦听器。您可以使用它.publish().refCount()Observable维护与其源的单个连接。

在 Bacon.js 中,Observables 始终保持与其源的单一连接。

在这两个库中,与源的连接都是延迟创建的(当Observer添加 an 时),并在删除(最后一个)Observer 时自动删除。因此,您不必手动管理侦听器。

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

就个人而言,我经常创建一个Observable被调用death或其他任何东西来表示观察者的生命结束,然后而不是订阅subject我订阅的subject.takeUntil(death).

关于 Elm,我的理解是你的整个事件网络都是一次性搭建好的,所以没有泄露的可能;Observers不能在后期添加。

于 2014-11-04T11:48:37.437 回答