除了缩减了view定义的代码,Marionette所有view中还有些先进的内存管理功能,使得view实例的清除工作和事件处理更容易了。
看下面的view实现:
var ZombieView = Backbone.View.extend({ template: '#my-view-template', initialize: function(){ // bind the model change to re-render this view this.model.on('change', this.render, this); }, render: function(){ // This alert is going to demonstrate a problem alert('We`re rendering the view'); } });
如果我们用相同的变量名称创建这个view的两个实例,然后修改model中的一个值,能看到几次警告框?
创建两个view实例
var myModel = new MyModel({ firstName: 'Jeremy', lastName: 'Ashkenas', email: '[email protected]' }); // create the first view instance var zombieView = new ZombieView({ model: myModel }) // create a second view instance, re-using // the same variable name to store it zombieView = new ZombieView({ model: myModel }) myModel.set('email', '[email protected]');
按常理,因为两个实例都用zombieView 变量名,所以view的第二个实例创建后,第一个实例立马就会落到作用域之外。Javascript可以通过垃圾收集把它清除掉,也就是说第一个view实例不再有用,也不会对模型的“change”事件作出响应。
但运行这段代码时,警告框还是出现了两次!
出现这种问题,是因为model事件绑定是在view的initialize 方法中。无论什么时候把this.render当做回调方法传给model的 on 事件绑定,model也会得到一个对view实例的直接引用。就是因为model中有对view实例的引用,所以即使换掉 zombieView变量引用的view实例,不再被 zombieView引用的view实例也不会落到作用域之外。前面说过了,model中还有对它的直接引用。
既然最初那个view还在作用域内,第二个view实例也在,两个实例自然都会对model中的数据修改做出响应。
解决这个问题很简单。只要在用完view后调用model上的off 方法,让这个事件绑定处于准关闭的状态就行。为此,要在view里加个close 方法。
增加close方法的View定义
var ZombieView = Backbone.View.extend({ template: '#my-view-template', initialize: function(){ // bind the model change to re-render this view this.model.on('change', this.render, this); }, close: function(){ this.model.off('change', this.render, this); }, render: function(){ // This alert is going to demonstrate a problem alert('We`re rendering the view'); } });
不再需要第一个实例后,只需在其上调用close方法就行,活着的view实例就只剩一个了。
close方法演示
var myModel = new MyModel({ firstName: 'Jeremy', lastName: 'Ashkenas', email: '[email protected]' }); // create the first view instance var zombieView = new ZombieView({ model: myModel }) zombieView.close(); // double-tap the zombie // create a second view instance, re-using // the same variable name to store it zombieView = new ZombieView({ model: myModel }) myModel.set('email', '[email protected]');
再运行代码,就只剩一个警告框了。
有了Marionette,我们就不用自己写代码关闭事件处理器了。
Marionette的内存管理
var ZombieView = Marionette.ItemView.extend({ template: '#my-view-template', initialize: function(){ // bind the model change to re-render this view this.bindTo(this.model, 'change', this.render, this); }, render: function(){ // This alert is going to demonstrate a problem alert('We`re rendering the view'); } });
注意上面的代码,我们用bindTo方法取代了on方法。这个方法在Marionette的EventBinder对象中定义,在所有view类型中都能用。 bindTo 的方法签名跟on方法差不多,只是把触发事件的对象不再是调用者,而是变成了方法的第一个参数。
Marionette的view中还有一个 close方法,用来'off'掉事件的绑定。用bindTo设置的事件绑定会被自动关闭。也就是说我们不用亲自定义,和调用 close 方法,只要用bindTo 方法设置事件绑定,我们就可以放宽心,事件绑定会被自动'off'掉,我们的views也不会变成僵尸。
但view上 close 方法的自动调用是怎么实现的呢?什么时候,以及在哪调用它呢?请看Marionette.Region - 这是负责管理每个view生命周期的对象。
转自:http://www.ituring.com.cn/article/31721
转载请注明:阿尤博客 » Marionette:胜在内存管理(五)