JavaScript addEventListener

4
当我只使用一次addEventListener,例如在文件输入中,是否应该使用removeEventListener删除侦听器?或者如果我知道以后不会再使用任何代码,那么垃圾回收器将自动收集所有对象?
另外,如果我手动删除事件侦听器,那么它是否会加快垃圾回收器的速度,使其工作更轻松?
  var file    = document.querySelector('input[type=file]').files[0];
  var reader  = new FileReader();

  reader.addEventListener("load", function () {
    preview.src = reader.result;
  }, false);

  if (file) {
    reader.readAsDataURL(file);
  }

有更多的上下文会有所帮助。这段代码在哪里?例如,它是在一个函数中(例如,在输入的“change”处理程序中)吗? - T.J. Crowder
FYI,在一些最新的实现中,addEventListener 可以接收一个“options”对象作为第三个参数,让你设置一些东西,其中包括一个 once 标志,它将在事件第一次触发后删除侦听器。这可以被打补丁到尚不支持该行为的浏览器中。 - user1106925
1
请使用 src = URL.createObjectURL(file) 代替。 - Endless
3个回答

3

我应该使用 removeEventListener 来移除侦听器吗?

这完全取决于你。如果不移除,它将继续保持附加状态。

如果我知道我不再使用任何相关代码,那么垃圾收集器会自动回收所有对象吗?

只有当 FileReader 可以进行垃圾回收时才会回收。如果 reader 不符合 GC 的条件,则其处理程序仍然留存在内存中。

另外,如果我手动删除事件侦听器,是否会加速垃圾收集器的工作,使其更容易完成任务?

这取决于具体实现。

请注意,在您的示例中,您无法删除该处理程序。要删除它,您必须引用它。

以下是一个实际删除它的示例:

var file = document.querySelector('input[type=file]').files[0];
var reader;
var handler;
if (file) {
    reader  = new FileReader();
    handler = function () {
        preview.src = reader.result;

        // Remove this handler
        reader.removeEventListener("load", handler, false);
        reader = handler = null;
    };
    reader.addEventListener("load", handler, false);
    reader.readAsDataURL(file);
}

请注意,我们不仅从事件处理程序列表中删除对处理程序的引用,还从handler变量中删除对它的引用,并确保清除reader变量,以便读取器可以进行垃圾回收。
尽管如此,以上操作可能过于繁琐。只需清除reader即可:
var file = document.querySelector('input[type=file]').files[0];
var reader;
if (file) {
    reader  = new FileReader();
    reader.addEventListener("load", function () {
        preview.src = reader.result;

        reader = null;
    }, false);
    reader.readAsDataURL(file);
}

通过释放我们对 reader 的引用,我们使读取器有资格进行垃圾回收,这也将清理它的事件处理程序。

所以,你不建议在你确切知道垃圾回收器能处理的地方移除处理程序吗? - Alex Peterson
@AlexPeterson:我既不推荐也不反对。大多数情况下,我不这样做。如果我知道它会被清理干净,我就不觉得需要编写额外的代码。当然,有时候这意味着我是错误的,后来我意识到我应该编写那段代码 - 然后我就这样做了。:-) (虽然这只发生过两次 - 要么是因为我通常是正确的,要么 - 很可能 - 我没有注意到内存泄漏,因为它太小而不必担心。) - T.J. Crowder

0
如果您只使用监听器(即事件)一次,那么在使用后删除监听器是有意义的,特别是如果您对性能有所关注。

垃圾回收不会删除监听器,因为它不知道该事件是否会在未来再次发生。而且,由于它本身不会自动删除监听器,因此手动删除它并不能加快任何速度。

在事件内部删除它应该是一个相当干净的解决方案。

GC(垃圾回收器)知道事件是否会在未来发生,因此会将整个事情与附加的监听器一起收集起来。 - Alex Peterson

0
  1. 在未来不使用的事件上解除绑定处理程序并非强制性的,但手动解除绑定事件将会产生良好的解决方案/代码。

  2. JavaScript的垃圾回收机制会处理并释放保留的内存。它不会删除DOM元素上的事件监听器,这些元素可能仍然在分离的DOM树中引用它们。


它会加速垃圾回收吗? - Alex Peterson

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