gpt4 book ai didi

javascript - Backbone 僵尸观点和良好实践

转载 作者:数据小太阳 更新时间:2023-10-29 04:40:30 26 4
gpt4 key购买 nike

我对 backbone 还很陌生,我试图了解僵尸 View 的来龙去脉。

僵尸是,根据这个article :

When we bind objects together through events but we don’t bother unbinding them. As long as these objects are bound together, and there is a reference in our app code to at least one of them, they won’t be cleaned up or garbage collected. The resulting memory leaks are like the zombies of the movies – hiding in dark corners, waiting to jump out and eat us for lunch.

上面提到的文章建议创建一个对象来管理 View 之间的转换,然后实现一个关闭函数来删除和取消绑定(bind) View 。

也就是说,根据情况,从哪里调用关闭函数?

我在父 View 的初始化 block 中添加了一个属性来跟踪 subview 。这样我就可以在用新的替换它之前对其调用 .remove() 。这是好的做法还是有更好的方法?

我也不明白为什么要定义el然后用

渲染

this.$el.html(this.template(this.model.attributes));

不允许我取消绑定(bind) View ,而它按预期的方式工作

$('#sportsManDetails').html(this.$el.html(this.template(this.model.attributes)));

至于示例,我刚刚创建了一个简单的应用程序,它显示运动员姓名列表,并在单击姓名时显示更多详细信息。

这是代码和工作 fiddle :

html

<script id="nameListTemplate" type="text/template">
<%= first %> <%= last %>
</script>
<script id="sportsManDetailsTemplate" type="text/template">
<ul>
<li><%= first %></li>
<li><%= last %></li>
<li><%= age %></li>
<li><%= sport %></li>
<li><%= category %></li>
</ul>
<button class="test">Test</button>
</script>
<div id="sportsMenName"></div>
<div id="sportsManDetails"></div>

JS

模型和集合

var app = app || {};

app.SportsManModel = Backbone.Model.extend({});

app.SportsMenCollection = Backbone.Collection.extend({
model: app.SportsManModel
});

名称 View

app.NameView = Backbone.View.extend({
tagName: 'li',
className: 'sportsMan',
template: _.template($('#nameListTemplate').html()),

initialize: function(){
this.sportsManDetailsView;
},

events: {
'click': 'showSportsManDetails'
},

showSportsManDetails: function(e){
if (typeof this.sportsManDetailsView !== 'undefined'){
this.sportsManDetailsView.remove();
}
this.sportsManDetailsView = new app.SportsManDetailsView({
model: this.model
})
},

render: function(){
this.$el.append(this.template(this.model.attributes));
return this;
}
});

名称 ListView

app.NameListView = Backbone.View.extend({
el: '#sportsMenName',

initialize: function(sportsMen){
this.collection = new app.SportsMenCollection(sportsMen);
this.render();
},

render: function(){
this.collection.each(function(sportsMen){
this.renderContact(sportsMen);
}, this);
},

renderContact: function(sportsMen){
var nameView = new app.NameView({
model: sportsMen
});
this.$el.append(nameView.render().el);
}
});

SportsManDetailsView

app.SportsManDetailsView = Backbone.View.extend({
// doesn't work if I use el in conjunction with
// this.$el.html(this.template(this.model.attributes));
// el: '#sportsManDetails',
template: _.template($('#sportsManDetailsTemplate').html()),

initialize: function(){
this.render();
},

events: {
'click .test': 'test'
},

test: function(){
alert('test');
},

render: function(){
// that does not work
//this.$el.html(this.template(this.model.attributes));

// is this good practice?
$('#sportsManDetails').html(this.$el.html(this.template(this.model.attributes)));
}
});

app.js

var sportsMen = [
{first: 'Quentin', last: 'Tarant', age: '34', sport: 'bike', category: '- 90kg'},
{first: 'Aymeric', last: 'McArthur', age: '54', sport: 'jetski', category: '200HP'},
{first: 'Peter', last: 'TheFat', age: '45', sport: 'curling', category: 'dunno'},
{first: 'Charles', last: 'Martel', age: '21', sport: 'Moto', category: 'MX 250cc'},
];

$(function(){
new app.NameListView(sportsMen);
});

最佳答案

正如您所发现的,Backbone 认为自己更像是一个 而不是一个框架 - 它给开发人员留下了很多问题和设计模式。

术语“僵尸 View ”用于指定在您认为它们已死时仍然绑定(bind)到某物(因此还活着)的 View 。通常有来自 model.on 调用或类似的对 View 的剩余引用。基本上是一种特定形式的内存泄漏。

要管理 View 的生命周期,您可以使用父 View ,但通常的做法是从路由器执行此操作。路由器用于删除旧 View 并根据路由事件实例化新 View 。以下是我通常如何完成此操作的片段:

render: function(){
this.mainView && this.mainView.remove(); // if there is already a view, remove it
this.mainView = new SomeOtherKindOfViewDeterminedBySomeEvent(); // instantiate the new view
this.mainView.render();
this.mainView.$el.appendTo( '#main-content' ); // append it
}

一些注意事项:

  1. 如果不在 View 上显式调用 remove,您的应用程序将容易受到内存泄漏的影响。这是因为 View 的事件和属性仍然存在于后台。例如,如果你删除上面例子的第一行,我将失去对以前的 this.mainView 的引用,但它的事件仍在使用内存。随着时间的推移,这会对您的应用产生影响。
  2. 请注意,我在最后一行使用了 appendTo。在 View 上调用 remove 时,它的整个元素及其事件都会被移除。如果我只是这样做:

    this.mainView = new SomeOtherKindOfViewDeterminedBySomeEvent({ el: '#main-content' })

    然后在我调用 this.mainView 上的 remove 之后,#main-content 将从 DOM 中删除,所以我不能不再使用该选择器。通过附加它,我将 #main-content 保留为占位符,因此我可以继续向其附加 View 。 这就是您在尝试解除绑定(bind) SportsManDetailsView 然后再次渲染时看到的内容。

至于你的问题,这个:

$('#sportsManDetails').html(this.$el.html(this.template(this.model.attributes)));

不是好的做法。首先是您使用了全局 jQuery 对象,它破坏了 Backbone 的封装 View 方法。其次,从以前的 View 来看,事件在 DOM 中仍然处于事件状态,从而导致内存泄漏。单击“测试”按钮时可以看到这一点 - 每次实例化 SportsManDetailsView 时都会触发处理函数(第二次,警报消息将显示两次,然后显示三次,依此类推。 )

您应该依靠父 View 或路由器来处理此类交互。那,或者让你的 SportsManDetailsView 绑定(bind)到 #sportsManDetails 元素,永远不要删除它。然后,当您的 NameView 中发生点击事件时,让它的模型触发器触发一个事件。然后您的 SportsManDetailsView 可以监听相应集合中的事件并相应地重新呈现自己。 拥抱 Backbone 的事件!JavaScript 是一种事件驱动的语言,永远不要忘记您的大炮中有这些事件。

我已经更新了你的JSFiddle来展示我所说的一些内容。

关于javascript - Backbone 僵尸观点和良好实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25916009/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com