【问题标题】:Do Javascript event listeners need to be removed prior to removing the element they're attached to?Javascript 事件监听器是否需要在移除它们所附加的元素之前被移除?
【发布时间】:2024-01-21 19:07:01
【问题描述】:

假设我已将各种事件侦听器附加到各种表单元素。稍后,我想删除整个表单。

是否有必要(或建议)注销表单及其元素上存在的任何事件处理程序?如果是这样,删除元素集合上的所有侦听器的最简单方法是什么?不这样做会有什么后果?如果重要的话,我正在使用 Prototype。

这就是我实际在做的事情。我有一个简单的表格,像这样:

<form id="form">
  <input type="text" id="foo"/>
  <input type="text" id="bar"/>
</form>

我观察输入上的各种事件,例如:

$('foo').observe('keypress', onFooKeypress);
$('bar').observe('keypress', onBarKeypress);

等等

表单是通过 AJAX 提交的,响应是表单的新副本。我用新表单的副本替换旧表单,执行类似$('form').replace(newForm) 的操作。我是在积累一堆事件吗?

【问题讨论】:

    标签: javascript events event-handling prototypejs dom-events


    【解决方案1】:

    未注册的事件可能不会自动释放其内存。这在旧版本的 IE 中尤其存在。

    原型曾经有一个自动垃圾收集系统,但该方法已在 1.6 版中删除。它记录在here。删除该方法是否意味着不再进行垃圾收集,或者该方法不再公开可用,我不知道。另请注意,它仅在页面卸载时调用,这意味着如果您的用户在执行大量 AJAX 和 DOM 更新时长时间停留在同一页面上,即使在该页面访问期间,内存也可能泄漏到不可接受的程度。

    【讨论】:

      【解决方案2】:

      如果出现下面 Jonas 提到的场景,最好从从 DOM 中删除的元素中删除任何事件侦听器。

      【讨论】:

        【解决方案3】:

        是的,有点。这还不足以成为一个大问题,但在这种情况下,旧版本的 IE 会泄漏。

        从 Prototype 1.6.1(目前处于其最终候选版本中)开始,该库在页面卸载时处理此清理。当您使用 Prototype 添加事件观察器时,它会在数组中保留对该元素的引用;在页面卸载时,它会遍历该数组并删除所有观察者。

        但是,如果用户要在此页面上停留一段时间,内存使用量将在页面的整个生命周期内累积。您有多种选择:

        1. 监听表单的一个祖先上的事件,一个永远不会被替换的事件。然后,在您的处理程序中,检查事件的来源。 (即“事件委托”)

        2. 在致电Element#replace 之前明确取消注册您的所有呼叫。在你的例子中,你会这样做:

          $('foo', 'bar').each(Element.stopObserving);
          

        这相当于不带参数调用stopObserving,其效果是删除给定元素上的所有处理程序。

        我会推荐选项 1。

        (作为Element#updateElement#replace 的一部分,我们已经讨论过在未来版本的Prototype 中自动移除监听器,但这是一种性能权衡。)

        【讨论】: