Recién estoy comenzando con Knockout.js (siempre quise probarlo, ¡pero ahora finalmente tengo una excusa!). Sin embargo, me encuentro con algunos problemas de rendimiento realmente malos cuando vincula una tabla a un conjunto relativamente pequeño datos (alrededor de 400 filas más o menos).
En mi modelo, tengo el siguiente código:
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!
}
};
El problema es que el for
bucle anterior tarda unos 30 segundos más o menos con alrededor de 400 filas. Sin embargo, si cambio el código a:
this.loadData = function (data)
{
var testArray = []; //<-- Plain ol' Javascript array
for(var i = 0; i < data.length; i++)
{
testArray.push(new ResultRow(data[i]));
}
};
Luego, el for
bucle se completa en un abrir y cerrar de ojos. En otras palabras, el push
método del observableArray
objeto de Knockout es increíblemente lento.
Aquí está mi plantilla:
<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>
Mis preguntas:
- ¿Es esta la forma correcta de vincular mis datos (que provienen de un método AJAX) a una colección observable?
- Espero que
push
esté haciendo una recalculación pesada cada vez que lo llamo, como quizás reconstruir objetos DOM enlazados. ¿Hay alguna manera de retrasar este recalc o tal vez introducir todos mis elementos a la vez?
Puedo agregar más código si es necesario, pero estoy bastante seguro de que esto es lo relevante. En su mayor parte, solo estaba siguiendo los tutoriales de Knockout del sitio.
ACTUALIZAR:
Siguiendo los consejos a continuación, he actualizado mi código:
this.loadData = function (data)
{
var mappedData = $.map(data, function (item) { return new ResultRow(item) });
this.projects(mappedData);
};
Sin embargo, this.projects()
todavía se necesitan unos 10 segundos para 400 filas. Admito que no estoy seguro de qué tan rápido sería esto sin Knockout (solo agregando filas a través del DOM), pero tengo la sensación de que sería mucho más rápido que 10 segundos.
ACTUALIZACIÓN 2:
Según otros consejos a continuación, le di una oportunidad a jQuery.tmpl (que es compatible de forma nativa con KnockOut), y este motor de plantillas dibujará alrededor de 400 filas en poco más de 3 segundos. Este parece el mejor enfoque, salvo una solución que cargue dinámicamente más datos a medida que se desplaza.
fuente
valueHasMutated
hace. compruebe la respuesta si tiene tiempo.