创建一个新的DocumentFragment来预渲染所有项目,然后更新一次 DOM。
此外,更喜欢this.$(...)全局 jQuery 选择器$(...)。
this.$是一个this.$el.find(...)更有效的代理,并且不太可能选择视图之外的内容。
$()如果视图尚未呈现,则在视图中使用 jQuery 的核心函数 ( ) 可能会失败。因此,最好始终进行操作,this.$el以便您甚至可以在将视图实际放入 DOM 之前进行更改。
保留在数组中创建的所有子视图,以便以后干净地删除它们。
initialize: function() {
this.childViews = [];
},
render: function() {
// cache the list jQuery object
this.$list = this.$("#item-table");
// Make sure to destroy every child view explicitely
// to avoid memory leaks
this.cleanup();
this.renderCollection();
return this;
},
真正的优化从这里开始,使用临时容器。
renderCollection: function() {
var container = document.createDocumentFragment();
this.collection.each(function(model) {
// this appends to a in memory document
container.appendChild(this.renderItem(model, false).el);
}, this);
// Update the DOM only once every child view was rendered.
this.$list.html(container);
return this;
},
我们的renderItem函数仍然可以用于渲染单个项目视图并立即将其放入 DOM。但它也提供了一个选项来推迟 DOM 操作,它只返回视图。
renderItem: function(model, render) {
var view = new Item({ model: model });
this.childViews.push(view);
view.render();
if (render !== false) this.$list.append(view.el);
return view;
},
为了避免悬空侦听器的内存泄漏,重要的是remove在忘记它之前调用每个视图。
我通过延迟实际调用来使用额外的优化,remove这样我们就不会在用户等待时浪费时间。
cleanup: function() {
var _childViewsDump = [].concat(this.childViews);
this.childViews = [];
while (_childViewsDump.length > 0) {
var currentView = _childViewsDump.shift();
// defer the removal as it's less important for now than rendering.
_.defer(currentView.remove.bind(currentView), options);
}
}