不可能的骨干僵尸
我一直在努力调试我的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清理function:
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(); };
我尝试将View el
直接附加到body
并使用this.remove();
在View清理function中(而不是使用我附加元素的常用el: $('#content')
,然后通过this.$el.empty()
清理this.$el.empty()
),但是这样做也没有用。
它可能与我的“全球事件”有关:
Backbone.Events.on('letterMouseDown', this.letterMouseDown, this);
但我用onClose函数处理它们:
onClose: function() { Backbone.Events.off('letterMouseDown'); }
我看到的一个问题是你的close
函数永远不会从视图的el
删除事件委托者。 通过使用jQuery的委托forms来处理视图的事件on
以将单个事件处理程序附加到视图的el
。 你的close
:
this.$el.empty();
但是这只删除了附加到该内容的内容和任何事件处理程序,它对直接连接到this.el
的处理程序完全没有任何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
调用应该可以解决这个问题。
一般建议:
-
不要使用old-school
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; }
我很确定我找到了问题的根源。
mu太短是对的,用close()
方法我没有删除直接绑定到我的el
的事件(我试图通过this.off()
– this.$el.off()
/ this.undelegateEvents()
是正确的方法)。 但对我来说,它只解决了不必要地多次调用事件的问题。
我被“僵尸视图”或意外行为所困扰的原因是我没有释放视图中的记忆。
this.remove()
只删除el
和它的元素/事件,但不删除View的内部变量。 详细说明 – 在我的视图中我有一个声明如此this.array: []
的数组,并且我没有在onClose
函数中释放它。
我所要做的只是在onClose
函数中清空它或者最初将数组声明为this.array: null
所以在经常查看渲染时它至少会释放前一个数组(但它仍然应该在onClose
方法上释放,因为数组/对象仍然会停留在内存中,直到远离页面浏览)。
调试是令人难以忍受的 ,因为它是一个填字游戏(至少我的代码很难在那里阅读),有时单词不匹配,但我不知道问题来自哪里。
得到教训。