[英]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
may be called multiple times. createNewView
可以被多次调用。 My understanding is that the variable view
will not necessarily be removed by JavaScript's built-in garbage collection because it references objects/code which still exists when the createNewView
function completes. 我的理解是,变量
view
不一定会被JavaScript的内置垃圾回收删除,因为它引用了createNewView
函数完成时仍然存在的对象/代码。
Is this correct? 这个对吗? How to deal with this?
该如何处理?
My current approach is to initialise myView
once at the level of my app: 我目前的方法是在应用程序级别一次初始化
myView
:
myApp.view = new myView()
Then in createNewView
I just call render on this: 然后在
createNewView
我仅对此调用render:
myApp.view.render()
Essentially, I only ever have one of them and I re-use it. 本质上,我只有其中之一,并且我会重复使用它。
An alternative approach is to track the creation of sub views in an array and then I call .remove()
on each one in turn when I know they are no longer needed. 另一种方法是跟踪数组中子视图的创建,然后在我知道不再需要它们时依次对每个视图调用
.remove()
。
Am I on the right track? 我在正确的轨道上吗?
It occurs to me that the second approach is better because if myView
created bound callbacks on other objects with listenTo
, these would not be removed simply by re-assigning the variable. 在我看来,第二种方法更好,因为如果
myView
使用listenTo
在其他对象上创建了绑定回调,则仅通过重新分配变量就不会删除这些回调。 That is, if I am calling new
to instantiate a new instance of the view, I should call remove()
on the being discarded instance first... It seems. 也就是说,如果我要调用
new
来实例化视图的新实例,则应首先在被丢弃的实例上调用remove()
……似乎。
In your example, you don't put the view's el
into the DOM , so nothing is referencing the view, then it will be collected by the garbage collection. 在您的示例中,您没有将视图的
el
放入DOM ,因此没有任何东西引用该视图,然后它将被垃圾回收器收集。
One good thing to ensure a view isn't bound to something anymore is to call .remove()
on it . 确保视图不再绑定于某物的一个好处是在其上调用
.remove()
。 It will remove: 它将删除:
el
from the DOM, el
从DOM, The Backbone .remove
source : 骨干
.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(); },
As mentioned by mu is too short in the comments (and myself in almost every other answers), you should always favor listenTo
over on
or bind
to avoid memory leaks and ease unbinding events. 正如mu所提到的那样,注释太短了 (我自己几乎在所有其他答案中),您应该始终偏爱
listenTo
不是on
或bind
以避免内存泄漏并简化解除绑定的事件。
When rendering child views, nested inside a parent view, a good practice is to keep an array of the child views to later call .remove()
on each of them. 渲染嵌套在父视图内的子视图时,一个好的做法是保留一个子视图数组,以便以后在每个子视图上调用
.remove()
。
A simple list view might look like this: 一个简单的列表视图可能如下所示:
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 = [];
},
});
Though if other objects are listening to it, it won't be collected and may be a leak. 虽然如果其他对象在听,则不会被收集,可能是泄漏。 It's important to keep track of the references and delete them all when you don't need it anymore.
重要的是要跟踪引用,并在不再需要它们时将其全部删除。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.