骨干渲染这个。$ el.html(this.template(data))慢。该怎么办?

时间:2014-02-25 01:41:20

标签: backbone.js handlebars.js render

我有一个要展示的系列。

1. for each model in collection, create a View
2. append view.render().el

我发现view.render()需要很长时间,更具体地说 this.$el.html(this.template(data))部分。

我需要加快速度,发现'DOM操作'很慢 所以我找了批处理渲染的方法,但没有找到太多。

  • 问题1.
    我想知道是否有办法批量处理并将最终的html附加到DOM而不将每一行附加到DOM? (我怀疑这个。$ el.html()执行DOM操作。如果是这样,我可以以某种方式不在view.render()中执行this.$el.html()调用,然后分配视图的el以减少DOM交互吗?)

  • 问题2.
    在客户端浏览视图时是否还有其他陷阱或性能阻碍?

修改

  addAll: function() {

    this.$('#thread-loop').html('');

    var fragment = document.createDocumentFragment();
    for (var i = 0; i < this.threads.length; i++) {
      console.log('adding one');
      var thread = this.threads.at(i);
      var View = this.threadTypeToViewMap[thread.get('thread_type')];

      var view = new View( {model: thread, forumSelector: this.forumSelector} );

      fragment.appendChild(view.render().el);
    }
    this.$el.find('#thread-loop')[0].appendChild(fragment);

    // this.threads.each(this.addOne, this);

  },

实际上,我意识到我正在使用片段技术。

我更多地解决了这个问题,看起来当javascript对象具有冗长的属性(用户创建的数据)时,handlebar需要很长时间才能在template()调用中找到属性(或者我怀疑)。

4 个答案:

答案 0 :(得分:1)

查看http://marionettejs.com

他们扩展Backbone以提供针对集合优化的视图(因此您可以在循环中创建DOM节点,并在完成后仅将它们添加到文档中)。这对你的表现非常有帮助。

至于问题2,会给你带来陷阱的事情是:

  • 广泛的DOM操作
  • 在客户端而不是服务器上编译模板(即在加载页面后对每个模板进行单独请求)
  • 一般JavaScript性能瓶颈(例如,使用jQuery或下划线而不是本机JS等使用polyfill foreach循环)。

答案 1 :(得分:1)

骨干模板渲染速度很慢,因为默认情况下,它们使用JavaScript的with结构来正确调整变量名称的范围。 Backbone模板的一个鲜为人知的特性允许您通过分配变量来放置所有数据(通常只是“数据”)来跳过这个相当大的性能损失:

var t = _.template('<%= data.x %>', null, {variable: 'data'});
template({x: 42});

而不是正常:

_.template('<%= x %>');
template({x: 42});

执行此操作,您将看到巨大的性能提升。这可能会立即解决您的性能问题。

基准:http://jsperf.com/underscore-template-function-with-variable-setting

答案 2 :(得分:0)

对于Q1 - &gt; 如果您的$ el已经不在dom中,您可以将所有$ el附加到Document Fragment中,然后立即将Document Fragment注入页面。 JQuery的John Resig撰写了一篇关于文档片段如何工作的精彩文章:http://ejohn.org/blog/dom-documentfragments

答案 3 :(得分:0)

您可以尝试使用doc片段的几件事:

1-如果要使用for循环,请在循环之前缓存长度。 var threadLength = this.threads.length;

2-那就是说,我会选择使用_.each而不是for循环。

3-如果你做2,应该很容易访问线程模型。我不知道使用get()是否有任何命中,但你可以直接访问model.attributes.thread_type。

3-您的模板是否已缓存?

4-为什么要两次更改#thread-loop的html?需要吗?如果您需要访问它两次,那么也缓存该选择器。