javascript - Backbone.js fetch() büyük koleksiyon betiğin donmasına neden oluyor


Kullanıcının tüm işlerini gösteren bir Jobs tablo görünümüm var. Jobs koleksiyonunun fetch() işlemi potansiyel olarak binlerce kayıt döndürebilir. Bir test yaptım ve veritabanına 1000 Job kaydı ekledim ve koleksiyon üzerinde fetch() gerçekleştirdim. Ancak, 1000 kaydın tarayıcı tarafından işlenmesi çok fazla gibi görünüyor, çünkü 1000 DOM tablo satırı eklemek tarayıcının donmasına neden oluyor gibi gözüküyor.

Satırların render edilmesini daha hızlı yapacak daha iyi bir yol var mı? Her zaman kısmi bir fetch yapılabileceğini biliyorum (başlangıçta 100 kayıt çekmek ve kullanıcı ekranın altına kaydırdıkça ek olarak 100 kayıt daha çekmek), ama genellikle bu fikre karşıyım çünkü 100 kaydı aşağı kaydırmak ve ek 100 kaydın render edilmesini beklemek için 3-4 saniye beklemek, kötü bir kullanıcı deneyimi ile sonuçlanıyor gibi görünüyor.

İşte benim kodum:

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;
  }

});

Cevap #1

Her şey kullanıcının ne tür bir deneyime ihtiyaç duyduğuna, işlerle ne yapması gerekeceğine bağlıdır; sizin kullanıcınız, belirli bir iş arayan potansiyel bir iş adayı mı, yoksa kullanıcı işlerin yönetiminden sorumlu olan bir kişi olduğu bir çeşit yönetim uygulaması mı?

Genel olarak 1000 öğeyi tek sayfaya yerleştirmek kötü bir kullanıcı deneyimidir, aşağı kaydırıldıkça ek işleri yüklemekle çalışmak, Facebook, Twitter gibi son zamanlarda popüler bir özellik haline geldi... bu yorumlar için iyi olabilir ama işler başka bir şeydir, başlangıçtan sona atlamak için bir yol gereklidir, 10 kez "daha fazla" tıklamak veya 10 kez aşağı kaydırmak zorunda kalmadan.

olası çözümler:

  1. yani, sayfalama elbette başka bir seçenektir, bir telsiz kullanmak kesinlikle çok fazla öğe ile çalışmanın bir yoludur ve kişiye 1. sayfadan 10. sayfaya, diğer 9 sayfadan geçmeden geçme imkanı verir.
  2. Yapabileceğiniz bir diğer şey de filtreler eklemektir; bir kişi iş arayabilir: konum, firma, sektör, ... bu her zaman görünen koleksiyonun boyutunu azaltacaktır.

saf teknik çözümler:

Bu blog yazısını okumalısınız, başlangıçta bir koleksiyonun tüm öğelerini sadece 1 görünümde render ettiyseniz tıklanan tam öğeyi nasıl alacağınızı anlatıyor, ama burada ele alınan meseleye doğru ilerliyor: jobListView'e her iş için 1 olmak üzere 1000 ayrı görünüm eklenmesi veya bu işlerin jobListView içinde eklenmesi, böylece sadece 1 görünüm olması.

Doğru bir şekilde uygulanırsa, ikincisi uygulamanızın DOM ile etkileşimini büyük ölçüde azaltabilir. Doğru bir şekilde uygulandığında kastım, tüm işleri bir for döngüsünde eklemek, bunları bellekte bir tablo/listeye eklemek ve sadece en sonunda tabloyu/listeyi DOM'a eklemektir; bu, kodunuzu 1000 ekleme yerine 1 DOM etkileşimiyle sınırlar.

Evet, Derick aslında model başına 1 görünüm oluşturma konusunda daha eğilimli, ancak performans konusuna sadece küçük bir şekilde değiniyor: önce oluştur, sonra hızlı yap ifadesi, bu size herhangi bir çözüm sunmuyor. Ve eğer iş listeniz sadece bir listeleme ve iş detay sayfasına bir linkten ibaretse, çok fazla etkinlik yoksa, hepsini yönetmek için 1 görünüm seçeneği hâlâ çok geçerli.

Cevap #2

Zayıf performansınız muhtemelen satırları doğrudan DOM'a eklediğiniz içindir. Bunu her yaptığınızda tarayıcı yeniden akış gerçekleştirecektir.

Tabloyu hafızada oluşturur ve ardından tablo tamamlandıktan sonra tüm tabloyu DOM'a eklerdim.