我一直在努力调试我的Backbone多页面应用程序,以摆脱僵尸'但遗憾的是无济于事。在今天之前,我甚至没有意识到我有一个僵尸问题。我做错了什么?
这是我的RegionManager:
var regionManager = (function() {
var currView = null;
var rm = {};
var closeView = function(view) {
if (view && view.close) {
view.close();
}
};
var openView = function(view) {
view.render();
if (view.onShow) {
view.onShow();
}
};
rm.show = function(view) {
closeView(currView);
currView = view;
openView(currView);
};
return rm;
})();
这是我的View清理功能:
Backbone.View.prototype.close = function() {
if (this.onClose) {
this.onClose();
}
if (this.views) {
_.invoke(this.views, 'close');
}
// Unbind any view's events.
this.off();
// Unbind any model and collection events that the view is bound to.
if (this.model) {
this.model.off(null, null, this);
}
if (this.collection) {
this.collection.off(null, null, this);
}
// Clean up the HTML.
this.$el.empty();
};
我尝试将视图el
直接附加到body
并在视图清理功能中使用this.remove();
(而不是使用我所使用的公共el: $('#content')
我附加元素,然后按this.$el.empty()
清理,但这也不起作用。
这可能与我的"全球事件":
有关Backbone.Events.on('letterMouseDown', this.letterMouseDown, this);
但我用onClose函数处理它们:
onClose: function() {
Backbone.Events.off('letterMouseDown');
}
答案 0 :(得分:4)
我看到的一个问题是,您的close
函数永远不会从视图el
中删除事件委托人。通过使用jQuery的on
的委托者形式来处理视图的事件,以将单个事件处理程序附加到视图的el
。您的close
会:
this.$el.empty();
但是只删除附加到该内容的内容和任何事件处理程序,它对直接附加到this.el
的处理程序完全没有任何作用。考虑这个最小的例子:
var V = Backbone.View.extend({
events: {
'click': 'clicked'
},
clicked: function() {
console.log('still here');
}
});
var v = new V({ el: '#el' });
v.close();
之后,即使您认为视图已完全清理,单击#el
也会在控制台中抛出'still here'
。演示:http://jsfiddle.net/ambiguous/aqdq7pwm/
向close
添加undelegateEvents
来电应该可以解决这个问题。
一般建议:
不要将旧式on
和off
函数用于事件,而是使用listenTo
和stopListening
。 listenTo
会跟踪侦听器上的事件,以便以后更容易将其删除。
简化您的close
即可:
Backbone.View.prototype.close = function() {
if(this.onClose)
this.onClose();
if(this.views)
_.invoke(this.views, 'close');
this.remove();
};
不要将视图绑定到现有的el
。让视图创建(并拥有)自己的el
并让调用者将el
放入容器中,并按照惯例进行:
var v = new View();
container.append(v.render().el);
图案。如果您必须附加到现有el
,则视图应覆盖remove
,并略微修改标准实现版本:
remove: function() {
this.$el.empty(); // Instead of removing the element.
this.undelegateEvents(); // Manually detach the event delegator.
this.stopListening();
return this;
}
答案 1 :(得分:1)
我很确定我找到了问题的根源。
mu太短是对的,使用close()
方法我没有删除直接绑定到el
的事件(我试图通过this.off()
- {{1 } / this.$el.off()
是正确的方法)。但对我来说,它只解决了不必要地多次调用事件的问题。
我被'僵尸观点'或意外行为所困扰的原因是我没有释放视图中的记忆......
this.undelegateEvents()
只删除this.remove()
及其元素/事件,但不删除View的内部变量。详细说明 - 在我的视图中,我有一个声明为el
的数组,我没有在this.array: []
函数中释放它。
我所要做的就是在onClose
函数中将其清空,或者最初将数组声明为onClose
,这样在循环查看渲染时它至少会释放前一个数组(它仍然应该被释放)但是this.array: null
方法,因为数组/对象仍然会停留在内存中,直到离开页面为止。)
调试是难以忍受,因为它是一个填字游戏(至少我的代码很难在那里阅读),有时单词不匹配,但我不知道在哪里问题来自。
经验教训。