骨干内存泄漏删除不起作用?

时间:2016-03-22 09:33:31

标签: backbone.js memory-leaks

在路由器中我这样做

            function test()  {
                self.topbarView = new TopbarView();
                self.topbarView.render();
                GhostviewHunter.addView(self.topbarView);
            }

            function clean() {
                console.log(GhostviewHunter.currentViews.length);
                GhostviewHunter.clean();
            }
            setInterval(test, 1000);
            setInterval(clean, 1000);

ghostviewhunter应该清理/删除视图:

define('ghostviewHunter', [], function() {

    var GhostviewHunter = function() {};

    GhostviewHunter.prototype.currentViews = [];

    GhostviewHunter.prototype.addView = function(view) {
        this.currentViews.push(view);
    }

    GhostviewHunter.prototype.clean = function() {
        _.each(this.currentViews, function(view) {
            view.remove();
        });
        this.currentViews.length = 0;
    }

    GhostviewHunter.__instance = null;

    GhostviewHunter.getInstance = function() {
        if( GhostviewHunter.__instance == null ) {
            GhostviewHunter.__instance = new GhostviewHunter();
        } 
        return GhostviewHunter.__instance;
    }

    return GhostviewHunter.getInstance();

})

TopView正在获取模型,每隔1seconde使用setInterval函数更新模型。

我以为remove();当我监视应用程序时,内存泄漏非常快就足够了。

有什么想法吗?

编辑: TOPBARVIEW

define('topbarView', [
    'backbone',
    'parameterManager',
    'text!views/topbarView/topbarTemplate.html',
    'drupalidModel',
    'weatherModel',
    'refreshTime',
    'dateParser'
    ], function(Backbone, ParameterManager, TopbarTemplate, DrupalidModel, WeatherModel, RefreshTime, DateParser) {

    var TopbarView = Backbone.View.extend({
        el: '#topbar',

        template: _.template(TopbarTemplate),

        events: {},

        initialize: function() {
            var self = this;
            _.bindAll(this, 'render', 'startDateRefresh');
            this.dateParser = new DateParser();
            self.startDateRefresh();
            setInterval(self.startDateRefresh, RefreshTime.date);
            this.initWeatherModel();        
        },

        render: function() {
            var self = this;
            var data = {
                picto_url : ParameterManager.get('WEATHER_RESOURCE_URL') + ParameterManager.get('WEATHER_PICTO_CODE') + ".png",
                date: self.date
            }
            this.$el.html(this.template({data: data}));
        },

        initWeatherModel: function() {
            var self = this;
            var weather_url = ParameterManager.get('WEATHER_URL');

            if(weather_url === null) {
                this.drupalidModel = new DrupalidModel();
                this.drupalidModel.fetch({
                    success: function(model, response) {
                        var center_id_num = model.get('center_id_num');
                        ParameterManager.set('DRUPAL_CENTER_ID_NUM', center_id_num);
                        ParameterManager.constructWeatherUrl();
                        self.model = new WeatherModel();
                        self.listenTo(self.model,'change', self.render);
                        self.startModelRefresh();
                    },
                    error: function() {
                        console.log("Failed to fetch center id!");
                    }
                })
            } else {
                this.model = new WeatherModel();
                self.listenTo(self.model,'change', self.render);
                this.startModelRefresh();
            };
        },

        startModelRefresh: function() {
            var self = this;
            this.modelRefresh = function() {
                self.model.fetch();
            }.bind(this);
            self.modelRefresh();
            setInterval(self.modelRefresh, RefreshTime.weather);        
        },

        stopModelRefresh: function() {
            var self = this;
            clearInterval( self.modelRefresh );
        },

        startDateRefresh: function() {
            var self = this;
            this.date = this.dateParser.classicDate();
            this.render();
        }

    });

    return TopbarView;

})

1 个答案:

答案 0 :(得分:0)

正如fbynite建议的那样,你应该清除间隔的代码是不正确的,你应该将间隔id传递给clearInterval

除此之外,你根本不打电话给stopModelRefresh()。在删除视图之前,应确保已正确删除所有外部引用。例如,我添加了一个destroy方法,在删除视图之前清除间隔:

var TopbarView = Backbone.View.extend({
  el: '#topbar',
  template: _.template(TopbarTemplate),
  events: {},
  initialize: function() {
  },
  render: function() {
  },
  modelRefresh: function() {
    this.model.fetch();
  },
  startModelRefresh: function() {
    this.modelRefresh();
    this.intervalId = setInterval(_.bind(this.modelRefresh,this), RefreshTime.weather);
  },
  stopModelRefresh: function() {
    clearInterval(this.intervalId);
  },
  destroy: function() {
    this.stopModelRefresh();
    this.remove();
  }

});

现在,您的GhostviewHunter应该调用它,而不是直接调用remove

GhostviewHunter.prototype.clean = function() {
   _.each(this.currentViews, function(view) {
            view.destroy();
   });
   this.currentViews.length = 0;
}

或者您甚至可以将remove方法本身覆盖为:

remove: function(){
  this.stopThisInterval();
  this.stopThatInterval();
  this.cleanUpSomethingElse();
  Backbone.View.prototype.remove.call(this);
}

并且让幽灵的东西叫remove本身。

请注意,您还有其他间隔调用startDateRefresh,您甚至都没有尝试清除......您应该清除所有类似内容。

作为旁注,我强烈建议停止发送self = this垃圾邮件,例如:

stopModelRefresh: function() {
        var self = this;
        clearInterval( self.modelRefresh );
 // Why..? Nothing here changes the context?
},

并且我还建议在当前获取成功/失败后递归调用modelRefresh,而不是在您无法保证先前获取完成的时间间隔内调用它