我正在开发一个显示推文列表的Backbone 演示应用程序 。 当我用不同的数据替换所有“推文”时,我使用$.html()清除列表
render: function() { $("#item-table").html(''); this.collection.each(this.addItem); }我想知道是否有人可以给我一个提示,我可以替换这个$.html()以获得更好的性能,因为使用$.html()我会导致回流,并且会给出错误的布局处理时间。
代码中还有另外两个地方,我使用$.html() ,如果有人可以给我建议如果那些其他地方甚至是可能的话也会改变它们,这真的很棒。
I am working on a Backbone demo app that shows a list of tweets. As I am replacing all the "tweets" with different data I clear the list using $.html()
render: function() { $("#item-table").html(''); this.collection.each(this.addItem); }I was wondering if anyone could give me a hint with what can I replace this $.html() for better performance, because by using $.html() I am causing reflows and which gives bad layout process times.
There are two other places in the code where I use $.html() and it would be really great if someone could give me advice on how to change those too if those other places are even possible.
最满意答案
创建一个新的DocumentFragment以预渲染所有项目,然后更新DOM一次。
另外,在全局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是很重要的。
我通过推迟实际调用来使用额外的优化,因此我们不会在用户等待时浪费时间。
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); } }Create a new DocumentFragment to pre-render all the items, then update the DOM once.
Also, favor this.$(...) over the global jQuery selector $(...).
this.$ is a proxy to this.$el.find(...) which is more efficient, and less prone to select something outside of the view.
Using jQuery's core function ($()) inside a view can fail if the view wasn't rendered yet. So it's better to always manipulate through this.$el so you can make changes even before the view is actually put in the DOM.
Keep all the sub views created in an array to cleanly remove them later.
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; },The real optimization starts here, with a temporary container.
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; },Our renderItem function can still be used to render a single item view and immediatly put it in the DOM. But it also provides an option to postpone the DOM manipulation and it just returns the view.
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; },To avoid memory leaks with dangling listeners, it's important to call remove on each view before forgetting about it.
I use an additional optimization by deferring the actual call to remove so we don't waste time now while the user waits.
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); } }更多推荐
发布评论