【问题标题】:Backbone.js fetch() large collection causes script to freezeBackbone.js fetch() 大型集合导致脚本冻结
【发布时间】:2012-02-15 17:44:50
【问题描述】:

我有一个显示用户所有工作的工作表视图。 Jobs 集合 fetch() 可能返回包含数千条记录。我运行了一个测试并在数据库中插入了 1000 个作业记录,并对集合执行了 fetch()。然而,1000 条记录对于浏览器来说似乎太多了,因为插入 1000 条 DOM 表行似乎会导致浏览器冻结。

有没有更好的方法来优化行的呈现以使其执行得更快?我知道您总是可以进行部分提取(最初获取 100 条记录,并在每次用户滚动到屏幕底部时额外获取 100 条记录),但我通常反对这个想法,因为向下滚动 100 条记录并且必须等待 3 -4 秒再渲染另外 100 条记录似乎会导致糟糕的用户体验。

这是我的代码:

FM.Views.JobTable = Backbone.View.extend({
  initialize: function(){
    _.bindAll(this, 'render', 'refresh', 'appendItem');
    this.collection.bind('add', this.appendItem, this);
    this.collection.bind('reset', this.refresh, this);
  },

  render: function(){
    this.el = ich.JobTable({});
    $(this.el).addClass('loading');
    return this;
  },

  refresh: function(){
    $('tbody tr', this.el).remove();
    $(this.el).removeClass('loading');

    _(this.collection.models).each(function(item){ // in case collection is not empty
      this.appendItem(item);
    }, this);
    return this;    
  },

  appendItem: function(item){
    var jobRow = new FM.Views.JobTableRow({
      model: item
    });
    $('tbody', this.el).prepend(jobRow.render().el);
    $(jobRow).bind('FM_JobSelected', this.triggerSelected);
  }

});

FM.Views.JobTableRow = Backbone.View.extend({
  tagName: 'tr',

  initialize: function(){
    _.bindAll(this, 'render', 'remove', 'triggerSelected');
    this.model.bind('remove', this.remove);
  },

  render: function(){
    var j = this.model.toJSON();
    j.quantity = j.quantity ? number_format(j.quantity, 0) : '';
    j.date_start = date('M j Y', j.date_start);
    j.date_due = j.date_due ? date('M j Y', strtotime(j.date_due)) : '';
    j.paid_class = j.paid;
    j.status_class = j.status;
    j.paid = slug2words(j.paid);
    j.status = slug2words(j.status);

    this.el = ich.JobTableRow(j);
    $(this.el).bind('click', this.triggerSelected);
    return this;
  }

});

【问题讨论】:

    标签: javascript collections backbone.js render fetch


    【解决方案1】:

    您的性能不佳可能是因为您将行直接添加到 DOM。每次执行此操作时,浏览器都会重排。

    我会在内存中构建表格,然后在构建完成后将整个表格添加到 DOM。

    【讨论】:

      【解决方案2】:

      这一切都取决于用户需要什么样的体验,他将如何处理这些工作, 您的用户,是否是正在寻找某项工作的潜在求职者? 或者它是一种管理应用程序,用户是管理工作的人?

      一般来说,将 1000 个项目放在一页上是不好的用户体验,在向下滚动时加载额外的工作是现在的热门功能,比如 facebook、twitter ......这可能对 cme​​ts 有好处,但工作是另外一回事,需要一种无需点击“更多”10 次或向下滚动 10 次即可从头到尾跳转的方法。

      可能的解决方案:

      1. 因此,分页当然是另一种选择,使用分页器无疑是一种处理过多项目的方法,并且让人们可以从第 1 页跳转到第 10 页,而无需经过其他 9 页。
      2. 您可以做的另一件事是构建过滤器,可以按位置、公司、部门等搜索工作...这将减少始终可见的集合大小。

      纯技术解决方案:

      您应该阅读this blog post,它开始介绍如果您仅在 1 个视图中呈现集合的所有项目,如何从视图中获取确切点击的项目,但在这里演变成手头的问题, 每个作业有 1000 个单独的视图 1 个添加到 jobListView,或者将这些作业添加到 jobListView 中,因此只有 1 个视图。

      如果正确实施,后者可以大大减少您的应用与 DOM 的交互。正确实施我的意思是,在 for 循环中添加所有作业,通过将它们添加到内存中的表/列表中,并且仅在最后,将表/列表附加到 DOM 中,这将您的代码减少到 1 个 DOM 交互,而不是 1000 个追加。

      是的,Derick 确实更倾向于为每个模型渲染 1 个视图,尽管他不涉及性能主题,除了一个小问题:先制作然后制作快速声明,它不会为您提供任何解决方案。如果您的工作列表只是一个列表和一个指向工作详细信息页面的链接,没有很多事件,那么 1 view to rule them all 选项仍然非常有效。

      【讨论】:

      • 是的,但是 jquery 追加而不对 dom 本身进行操作会更快。即便如此,仍然有更好的解决方案,它可能看起来很脏,但是手动(或使用模板)构建您的 html 并执行 $(elem).html(myBuildUpHtmlString);甚至比你没有 1000 个追加更快。
      猜你喜欢
      • 1970-01-01
      • 2015-03-18
      • 1970-01-01
      • 2020-05-16
      • 2011-11-07
      • 1970-01-01
      • 2013-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多