在Backbone.js中实例化子视图时如何避免内存泄漏


myView =  Backbone.View.extend({
//event binding etc etc
render: function() {
//render some DOM
}
})
anotherView = Backbone.View.extend({
events: {
'click .selector doThis'
},
createNewView: function() {
var view = new myView();
}
})

CCD_ 1可以被调用多次。我的理解是,变量view不一定会被JavaScript的内置垃圾收集删除,因为它引用的对象/代码在createNewView函数完成时仍然存在。

这是正确的吗?如何处理?

我目前的方法是在我的应用程序级别初始化myView一次:

myApp.view = new myView()

然后在createNewView中,我只调用以下内容的render:

myApp.view.render()

从本质上讲,我只有一个,我会重复使用它

另一种方法是跟踪阵列中子视图的创建,然后当我知道不再需要它们时,依次对每个视图调用.remove()

我走对了吗?

我突然想到第二种方法更好,因为如果myView使用listenTo在其他对象上创建绑定回调,则不会简单地通过重新分配变量来删除这些回调。也就是说,如果我调用new来实例化视图的新实例,我应该首先对正在丢弃的实例调用createNewView0。。。看起来。

在您的示例中,您没有将视图的el放入DOM,因此没有任何内容引用该视图,然后它将被垃圾收集收集。

确保视图不再绑定到某个对象的一个好方法是对其调用.remove()。它将删除:

  • 来自DOM的视图的CCD_ 13
  • jQuery DOM事件
  • 骨干事件侦听器

骨干.remove来源:

// Remove this view by taking the element out of the DOM, and removing any
// applicable Backbone.Events listeners.
remove: function() {
this._removeElement();
this.stopListening();
return this;
},
// Remove this view's element from the document and all event listeners
// attached to it. Exposed for subclasses using an alternative DOM
// manipulation API.
_removeElement: function() {
this.$el.remove();
},

正如mu在评论中提到的太短(我在几乎所有其他回答中都提到了这一点),您应该始终支持listenTo而不是onbind,以避免内存泄漏并轻松解除绑定事件。

当呈现嵌套在父视图中的子视图时,一个好的做法是保留一个子视图数组,以便稍后在每个子视图上调用.remove()

一个简单的列表视图可能如下所示:

var ListView = Backbone.View.extend({
initialize: function() {
// Make an array available to keep all the child views
this.childViews = [];
},
addOne: function(model) {
var view = new Backbone.View({ model: model });
// as you create new views, keep a reference into the array.
this.childViews.push(view);
this.$el.append(view.render().el);
},
renderList: function() {
// replace the view content completely with the template
this.$el.html(this.templates());
// then cleanup
this.cleanup();
// then render child views
this.collection.each(this.addOne, this);
return this;
},
cleanup: function() {
// quick way to call remove on all views of an array
_.invoke(this.childViews, 'remove');
// empty the array
this.childViews = [];
},
});

尽管如果其他对象正在听它,它不会被收集,可能是泄漏。重要的是要跟踪引用,并在您不再需要时将其全部删除。

最新更新