不可能的骨干僵尸

时间:2015-10-18 16:59:33

标签: javascript jquery backbone.js

我一直在努力调试我的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');
}

2 个答案:

答案 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来电应该可以解决这个问题。

一般建议:

  1. 不要将旧式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;
    }
    

答案 1 :(得分:1)

我很确定我找到了问题的根源。

mu太短是对的,使用close()方法我没有删除直接绑定到el的事件(我试图通过this.off() - {{1 } / this.$el.off()是正确的方法)。但对我来说,它只解决了不必要地多次调用事件的问题。

我被'僵尸观点'或意外行为所困扰的原因是我没有释放视图中的记忆......

this.undelegateEvents()只删除this.remove()及其元素/事件,但不删除View的内部变量。详细说明 - 在我的视图中,我有一个声明为el的数组,我没有在this.array: []函数中释放它。

我所要做的就是在onClose函数中将其清空,或者最初将数组声明为onClose,这样在循环查看渲染时它至少会释放前一个数组(它仍然应该被释放)但是this.array: null方法,因为数组/对象仍然会停留在内存中,直到离开页面为止。)

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

经验教训。