$.empty() 对比 Backbone 的 View.remove()?

$.empty() vs Backbone's View.remove()?

我了解当通过 .remove() 删除视图时,会在该视图上调用 .stopListening() 以删除 Backbone 中与该视图关联的任何事件侦听器。来自 Backbone 文档:

删除 view.remove()

从 DOM 中删除一个视图,并调用 stopListening 以删除该视图已监听的任何绑定事件

我有附加到容器的视图,该容器仅包含与通过 Backbone 的事件挂钩对自身执行的 dom 操作相关的事件。

var View = Backbone.View.extend({
   events : {
      'input keyup' : 'searchDropdown'
   },

   searchDropdown: function () {
      $('dropdown').empty();
      //Appends views based on search
   }
});

我的问题是,当我在一个容器上调用 $.empty() 时,我是否泄漏了任何内存(重要的或不重要的),该容器有效地删除了附加在其中的视图。如果我是,在这些视图上访问和调用 .remove() 是否有任何好的约定?

您不需要为此使用任何特殊框架,但正确实施删除是个好主意,而不是依赖于足够智能的浏览器来执行此操作。有时在大型应用程序中,您会发现您特别需要重写 remove 方法来执行一些特殊的清理工作——例如,您在该视图中使用的库具有 destroy 方法。

现代浏览器往往有一个 GC,它在大多数情况下都足够智能,但我仍然不想依赖它。最近我参与了 Backbone 中的一个项目,该项目没有子视图的概念,我通过从 empty 更改为 remove 将泄漏节点减少了 50%(在 Chrome 43 ).很难让大型 javascript 应用程序不泄漏内存,我的建议是尽早对其进行监控:If a DOM Element is removed, are its listeners also removed from memory?

注意会泄漏大量内存的东西 - 例如图像。我在一个项目上有一些代码做了这样的事情:

var image = new Image();

image.onLoad(.. reference `image` ..)

image.src = ...

基本上是一个预加载器。因为我们没有明确地执行 image = null GC 从未启动,因为回调引用了 image 变量。在图像繁重的网站上,我们会在每次页面转换时泄漏 1-2mb,这会导致手机崩溃。在 remove 覆盖中将变量设置为 null 修复了此问题。

在子视图上调用 remove 就像做这样的事情一样简单:

remove: function() {
    this.removeSubviews();
    Backbone.View.prototype.remove.call(this);
},

removeSubviews: function() {
    if (!_.isEmpty(this.subViews)) {
         _.invoke(this.subViews, 'remove');
         this.subViews = []; 
    }
}

您只需要将您的子视图实例添加到一个数组中。例如,当您创建一个子视图时,您可以使用 parentView: this 之类的选项并将其添加到父视图的数组中。我过去做过更复杂的子视图系统,但那会很好用。在初始化视图时,您可以执行以下操作:

var parentView = this.options.parentView;
if (parentView) {
    (parentView.subViews = parentView.subViews || []).push(this);
}