javascript - Backbone.js fetch() stor samling orsakar att skriptet fryser


Jag har en Jobs-tabellvy som visar alla jobb för en användare. Jobs-samlingens fetch() kan potentiellt returnera tusentals poster. Jag gjorde ett test och lade till 1000 Job-poster i databasen och utförde en fetch() på samlingen. Dock verkar 1000 poster vara för mycket för att webbläsaren ska hantera eftersom insättning av 1000 DOM-tabellrader verkar få webbläsaren att frysa.

Finns det ett bättre sätt att optimera renderingen av raderna så att det går snabbare? Jag vet att man alltid kan göra en partiell hämtning (hämta initialt 100 poster och dessutom hämta 100 poster varje gång användaren skrollar till botten av skärmen), men jag är generellt emot den idén eftersom det att skrolla ner 100 poster och behöva vänta 3-4 sekunder innan ytterligare 100 poster renderas verkar ge en dålig användarupplevelse.

Här är min kod:

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

});

Svar #1

allt beror på vilken erfarenhet användaren behöver, vad han kommer att göra med jobben, din användare, är det en potentiell jobbkandidat som letar efter ett visst jobb? eller är det en slags administrationsapp där användaren är någon som hanterar jobb?

generellt sett är det dålig användarupplevelse att lägga 1000 objekt på en sida, att arbeta med att ladda ytterligare jobb när man scrollar ner är en slags het funktion nuförtiden som på Facebook, Twitter... detta kan vara bra för kommentarer men jobb är något annat, man behöver ett sätt att hoppa från början till slut utan att behöva klicka på "mer" 10 gånger, eller scrolla ner 10 gånger.

möjliga lösningar:

  1. så, sidnumrering är förstås ett annat alternativ, att använda en personsökare är definitivt ett sätt att arbeta med för många objekt, och ge personen ett sätt att hoppa från sida 1 till 10 utan att gå igenom de 9 andra.
  2. En annan sak du kan göra är att bygga in filter, man kan söka jobb efter: plats, företag, sektor, ... detta kommer att minska storleken på den samling som är synlig hela tiden.

rena tekniska lösningar:

du bör läsa igenom det här blogginlägget, det börjar med hur man får det exakt klickade objektet från en vy om du renderade alla objekt i en samling i bara en vy, men utvecklas till den aktuella frågan här, att ha 1000 separata vyer, 1 per jobb som läggs till i jobListView, eller att ha dessa jobb tillagda inom jobListView så att det bara finns 1 vy.

Den senare kan, om den implementeras korrekt, kraftigt minska din apps interaktion med DOM. Med 'implementeras korrekt' menar jag att lägga till alla jobb i en for-loop, genom att lägga dem i en tabell/lista i minnet, och först i slutet, fästa tabellen/listan i DOM, detta minskar din kod till 1 DOM-interaktion, istället för 1000 tillägg.

Ja, Derick lutar mer åt att rendera 1 vy per modell, även om han inte berör ämnet prestanda förutom en liten: först skapa det sedan gör det snabbt-uttalande som inte ger några lösningar för dig. Och om din lista över jobb bara är en uppräkning och en länk till en jobbdetaljsida, utan många händelser, är alternativet med 1 vy som styr dem alla fortfarande mycket giltigt.

Svar #2

Din dåliga prestanda beror förmodligen på att du lägger till rader direkt i DOM:en. Varje gång du gör detta kommer webbläsaren att omflöda.

Jag skulle bygga tabellen i minnet och sedan lägga till hela tabellen i DOM när den är konstruerad.