86 votes

Knockout.js incroyablement lent, en vertu de semi-grands ensembles de données

Je suis juste de commencer avec Knockout.js (toujours voulu essayer, mais maintenant que j'ai enfin une excuse!) - Cependant, je suis en cours d'exécution dans certains vraiment mauvais problèmes de performances lors de la liaison d'un tableau à un petit ensemble de données (autour de 400 lignes).

Dans mon modèle, j'ai le code suivant:

this.projects = ko.observableArray( [] ); //Bind to empty array at startup

this.loadData = function (data) //Called when AJAX method returns
{
   for(var i = 0; i < data.length; i++)
   {
      this.projects.push(new ResultRow(data[i])); //<-- Bottleneck!
   }
};

Le problème est l' for boucle ci-dessus prend environ 30 secondes ou si, avec près de 400 lignes. Cependant, si je change le code:

this.loadData = function (data)
{
   var testArray = []; //<-- Plain ol' Javascript array
   for(var i = 0; i < data.length; i++)
   {
      testArray.push(new ResultRow(data[i]));
   }
};

Puis l' for boucle se termine en un clin d'œil. En d'autres termes, l' push méthode de knock-out de l' observableArray objet est incroyablement lent.

Voici mon template:

<tbody data-bind="foreach: projects">
    <tr>
       <td data-bind="text: code"></td>
       <td><a data-bind="projlink: key, text: projname"></td>
       <td data-bind="text: request"></td>
       <td data-bind="text: stage"></td>
       <td data-bind="text: type"></td>
       <td data-bind="text: launch"></td>
       <td><a data-bind="mailto: ownerEmail, text: owner"></a></td>
    </tr>
</tbody>

Mes Questions:

  1. Est-ce la bonne manière de lier mes données (qui provient d'une méthode AJAX) pour une collection observable?
  2. J'attends push est en train de faire la grosse re-calc chaque fois que j'appelle, comme peut-être la reconstruction lié objets DOM. Est-il un moyen de retarder ce recalcul, ou peut-être pousser dans tous mes articles à la fois?

Je peux ajouter plus de code si nécessaire, mais je suis sûr que c'est ce qui est pertinent. Pour la plupart, j'étais juste Ko suivante tutoriels du site.

Mise à JOUR:

Par les conseils ci-dessous, j'ai mis à jour mon code:

this.loadData = function (data)
{
   var mappedData = $.map(data, function (item) { return new ResultRow(item) });
   this.projects(mappedData);
};

Toutefois, this.projects() encore faut environ 10 secondes pour 400 lignes. J'admets que je ne suis pas sûr de savoir comment rapide ce serait sans knock-out (ajouter des lignes à travers les DOM), mais j'ai le sentiment qu'il serait beaucoup plus vite que 10 secondes.

Mise à JOUR 2:

Pour d'autres conseils ci-dessous, j'ai donné jQuery.tmpl un coup (ce qui est pris en charge nativement par knock-out), et ce moteur de template va dessiner autour de 400 lignes dans un peu plus de 3 secondes. Cela semble être la meilleure approche, au court d'une solution qui permettrait de charger dynamiquement en plus de données que vous faites défiler.

50voto

Jim G. Points 4849

Veuillez voir: Knockout.js Performance Gotcha #2 - la Manipulation de observableArrays

Un meilleur modèle est d'obtenir une référence à notre tableau, pousser, puis de les appeler .valueHasMutated(). Maintenant, nos abonnés ne reçoivent une notification indiquant que le tableau a changé.

16voto

madcapnmckay Points 8477

Comme suggéré dans les commentaires.

Knock-out a son propre moteur de template natif associé à l' (foreach) avec) les liaisons. Il prend également en charge d'autres moteurs de template, à savoir jquery.tmpl. Lire ici pour plus de détails. Je n'ai pas fait la comparaison avec des moteurs différents, donc ne sais pas si elle va l'aider. La lecture de votre commentaire précédent, dans IE7-vous de la difficulté à obtenir les résultats que vous êtes après.

En aparté, KO prend en charge toute js moteur de template, si quelqu'un a écrit l'adaptateur pour qui est. Vous pouvez essayer d'autres comme jquery-tmpl est due à être remplacé par JsRender.

13voto

Tim Santeford Points 10126

L'utilisation de la pagination avec un KO en plus de l'utilisation de $.carte.

J'ai eu le même problème avec un de grands ensembles de données de 1400 dossiers jusqu'à ce que j'ai utilisé la pagination avec knock-out. À l'aide de $.map de charger le dossier ne fait faire une énorme différence, mais le DOM, le temps de rendu est toujours affreux. Alors j'ai essayé d'utiliser la pagination et qui a fait mon dataset éclairage rapide que-bien que de plus en plus conviviale. D'une taille de page 50 le jeu de données beaucoup moins écrasante et réduit le nombre d'éléments du DOM de façon spectaculaire.

Il est très facile à faire avec un KO:

http://jsfiddle.net/rniemeyer/5Xr2X/

11voto

deltree Points 1743

KnockoutJS a quelques très bons tutoriels, en particulier la une seule sur le chargement et l'enregistrement des données

Dans leur cas, ils tirent les données à l'aide d' getJSON() , ce qui est extrêmement rapide. De leur exemple:

function TaskListViewModel() {
    // ... leave the existing code unchanged ...

    // Load initial state from server, convert it to Task instances, then populate self.tasks
    $.getJSON("/tasks", function(allData) {
        var mappedTasks = $.map(allData, function(item) { return new Task(item) });
        self.tasks(mappedTasks);
    });    
}

9voto

ericb Points 2012

Donner KoGrid un coup d'oeil. Il gère intelligemment votre ligne de rendu de sorte qu'il est plus performant.

Si vous vous essayez de lier 400 lignes à une table à l'aide d'un foreach de la liaison, vous allez avoir de la difficulté à pousser beaucoup par KO dans les DOM.

KO fait des choses très intéressantes à l'aide de l' foreach de liaison, dont la plupart sont de très bonnes opérations, mais ils commencent à se briser sur les perf que la taille de votre tableau de pousse.

J'ai été vers le bas le long de la route sombre de tenter de lier les grands ensembles de données dans des tables/grilles, et vous finissez par avoir besoin pour briser/page les données localement.

KoGrid est-ce que tous. Il a été construit à seulement rendre les lignes, que le spectateur peut voir sur la page, puis virtualiser les autres lignes jusqu'à ce qu'ils sont nécessaires. Je pense que vous allez trouver sa perf sur 400 articles à être beaucoup mieux que vous êtes en train de vivre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X