在 Backbone.js 中实例化子视图时如何避免内存泄漏
How to avoid a memory leak when instantiating child views in 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();
}
})
createNewView
可能会被多次调用。我的理解是,变量 view
不一定会被 JavaScript 的内置垃圾收集器删除,因为它引用 objects/code,而 objects/code 在 createNewView
函数完成时仍然存在。
这是正确的吗?如何处理?
我目前的方法是在我的应用级别初始化 myView
一次:
myApp.view = new myView()
然后在 createNewView
中我只是调用渲染:
myApp.view.render()
基本上,我只有其中之一,我会重复使用它。
另一种方法是跟踪数组中子视图的创建,然后当我知道不再需要它们时,依次对每个子视图调用 .remove()
。
我走在正确的轨道上吗?
我觉得第二种方法更好,因为如果 myView
使用 listenTo
在其他对象上创建绑定回调,则不会通过重新分配变量简单地删除这些回调。也就是说,如果我调用 new
来实例化视图的新实例,我应该先在被丢弃的实例上调用 remove()
……看来。
在您的示例中,您没有将视图的 el
放入 DOM,因此没有任何内容引用该视图,那么它将是由垃圾收集器收集。
确保视图不再绑定到某物的一件好事是 对其调用 .remove()
。它将删除:
- 视图的
el
来自 DOM、
- jQueryDOM事件
- Backbone 事件侦听器。
Backbone .remove
source:
// 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();
},
如 (and myself in almost every other answers), you should always favor listenTo
over on
or bind
所述,以避免内存泄漏并简化解除绑定事件。
渲染嵌套在父视图中的子视图时,一个好的做法是保留一个子视图数组,以便稍后对每个子视图调用 .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 = [];
},
});
虽然如果其他对象正在监听它,它不会被收集并且可能是泄漏。跟踪引用并在您不再需要时将其全部删除是很重要的。
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();
}
})
createNewView
可能会被多次调用。我的理解是,变量 view
不一定会被 JavaScript 的内置垃圾收集器删除,因为它引用 objects/code,而 objects/code 在 createNewView
函数完成时仍然存在。
这是正确的吗?如何处理?
我目前的方法是在我的应用级别初始化 myView
一次:
myApp.view = new myView()
然后在 createNewView
中我只是调用渲染:
myApp.view.render()
基本上,我只有其中之一,我会重复使用它。
另一种方法是跟踪数组中子视图的创建,然后当我知道不再需要它们时,依次对每个子视图调用 .remove()
。
我走在正确的轨道上吗?
我觉得第二种方法更好,因为如果 myView
使用 listenTo
在其他对象上创建绑定回调,则不会通过重新分配变量简单地删除这些回调。也就是说,如果我调用 new
来实例化视图的新实例,我应该先在被丢弃的实例上调用 remove()
……看来。
在您的示例中,您没有将视图的 el
放入 DOM,因此没有任何内容引用该视图,那么它将是由垃圾收集器收集。
确保视图不再绑定到某物的一件好事是 对其调用 .remove()
。它将删除:
- 视图的
el
来自 DOM、 - jQueryDOM事件
- Backbone 事件侦听器。
Backbone .remove
source:
// 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(); },
如 listenTo
over on
or bind
所述,以避免内存泄漏并简化解除绑定事件。
渲染嵌套在父视图中的子视图时,一个好的做法是保留一个子视图数组,以便稍后对每个子视图调用 .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 = [];
},
});
虽然如果其他对象正在监听它,它不会被收集并且可能是泄漏。跟踪引用并在您不再需要时将其全部删除是很重要的。