不可能的骨干僵尸

我一直在努力调试我的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调用应该可以解决这个问题。


一般建议:

  1. 不要使用old-school onoff函数进行事件,而是使用listenTostopListeninglistenTo跟踪侦听器上的事件,以便以后更容易删除它们。

  2. 简化您的close

     Backbone.View.prototype.close = function() { if(this.onClose) this.onClose(); if(this.views) _.invoke(this.views, 'close'); this.remove(); }; 
  3. 不要将视图绑定到现有的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方法上释放,因为数组/对象仍然会停留在内存中,直到远离页面浏览)。

调试是令人难以忍受的 ,因为它是一个填字游戏(至少我的代码很难在那里阅读),有时单词不匹配,但我不知道问题来自哪里。

得到教训。