enfrentando problemas de rendimiento con el complemento de mapeo knockout
Frecuentes
Visto 3,627 equipos
2
Tengo un gran conjunto de datos decente de alrededor de 1100 registros. Este conjunto de datos se asigna a una matriz observable que luego se vincula a una vista. Dado que estos registros se actualizan con frecuencia, la matriz observable se actualiza cada vez que se usa el ayudante ko.mapping.fromJS.
Este comando en particular tarda alrededor de 40 segundos en procesar todas las filas. La interfaz de usuario solo se bloquea durante ese período de tiempo.
Aquí está el código:
var transactionList = ko.mapping.fromJS([]);
//Getting the latest transactions which are around 1100 in number;
var data = storage.transactions();
//Mapping the data to the observable array, which takes around 40s
ko.mapping.fromJS(data,transactionList)
¿Hay una solución para esto? ¿O debería simplemente optar por trabajadores web para mejorar el rendimiento?
4 Respuestas
1
Knockout.viewmodel es un reemplazo para knockout.mapping que es significativamente más rápido en la creación de modelos de vista para matrices de objetos grandes como esta. Debería notar un aumento significativo en el rendimiento.
Respondido el 26 de diciembre de 12 a las 22:12
0
También he pensado en una solución de la siguiente manera, esto usa menos cantidad de código:
var transactionList = ko.mapping.fromJS([]);
//Getting the latest transactions which are around 1100 in number;
var data = storage.transactions();
//Mapping the data to the observable array, which takes around 40s
// Instead of - ko.mapping.fromJS(data,transactionList)
var i = 0;
//clear the list completely first
transactionList.destroyAll();
//Set an interval of 0 and keep pushing the content to the list one by one.
var interval = setInterval(function () {if (i == data.length - 1 ) {
clearInterval(interval);}
transactionList.push(ko.mapping.fromJS(data[i++]));
}, 0);
Respondido el 07 de Septiembre de 12 a las 10:09
0
Tuve el mismo problema con el complemento de mapeo. El equipo de Knockout dice que el complemento de mapeo no está diseñado para funcionar con arreglos grandes. Si tiene que cargar datos tan grandes en la página, es probable que tenga un diseño inadecuado del sistema.
La mejor manera de solucionar esto es usar la paginación del servidor en lugar de cargar todos los datos en la carga de la página. Si no desea cambiar el diseño de su aplicación, existen algunas soluciones alternativas que tal vez lo ayuden:
Asigne su matriz manualmente:
var data = storage.transactions(); var mappedData = ko.utils.arrayMap(data , function(item){ return ko.mapping.fromJS(item); }); var transactionList = ko.observableArray(mappedData);
Asignar matriz de forma asíncrona. He escrito una función que procesa la matriz por partes en otro hilo e informa el progreso al usuario:
function processArrayAsync(array, itemFunc, afterStepFunc, finishFunc) { var itemsPerStep = 20; var processor = new function () { var self = this; self.array = array; self.processedCount = 0; self.itemFunc = itemFunc; self.afterStepFunc = afterStepFunc; self.finishFunc = finishFunc; self.step = function () { var tillCount = Math.min(self.processedCount + itemsPerStep, self.array.length); for (; self.processedCount < tillCount; self.processedCount++) { self.itemFunc(self.array[self.processedCount], self.processedCount); } self.afterStepFunc(self.processedCount); if (self.processedCount < self.array.length - 1) setTimeout(self.step, 1); else self.finishFunc(); }; }; processor.step(); };
Tu codigo:
var data = storage.transactions();
var transactionList = ko.observableArray([]);
processArrayAsync(data,
function (item) { // Step function
var transaction = ko.mapping.fromJS(item);
transactionList().push(transaction);
},
function (processedCount) {
var percent = Math.ceil(processedCount * 100 / data.length);
// Show progress to the user.
ShowMessage(percent);
},
function () { // Final function
// This function will fire when all data are mapped. Do some work (i.e. Apply bindings).
});
También puede probar la biblioteca de mapeo alternativa: knockout.wrap. Debería ser más rápido que el complemento de mapeo.
He elegido la segunda opción.
Respondido 21 ago 13, 02:08
Solución muy interesante. Sería interesante crear un JsPerf para ver cuánto más rápido puede llegar. - porra
@billy Tenga cuidado al editar publicaciones. Cambiar el estilo de codificación de la pregunta original se considera lo mismo que cambiar el significado de la publicación. Retrocedí la edición. - Lundín
Aquí está el jsperf: jsperf.com/… (Soy el autor del mapeador personalizado que se está probando) - Aymeric Gaurat-Apelli
0
El mapeo no es magia. En la mayoría de los casos esta simple función recursiva puede ser suficiente:
function MyMapJS(a_what, a_path)
{
a_path = a_path || [];
if (a_what != null && a_what.constructor == Object)
{
var result = {};
for (var key in a_what)
result[key] = MyMapJS(a_what[key], a_path.concat(key));
return result;
}
if (a_what != null && a_what.constructor == Array)
{
var result = ko.observableArray();
for (var index in a_what)
result.push(MyMapJS(a_what[index], a_path.concat(index)));
return result;
}
// Write your condition here:
switch (a_path[a_path.length-1])
{
case 'mapThisProperty':
case 'andAlsoThisOne':
result = ko.observable(a_what);
break;
default:
result = a_what;
break;
}
return result;
}
El código anterior hace observables desde el mapaEstaPropiedad y y también este propiedades en cualquier nivel de la jerarquía de objetos; otras propiedades se dejan constantes. Puede expresar condiciones más complejas usando a_ruta.longitud para el nivel (profundidad) en el que se encuentra el valor, o usando más elementos de un sendero. Por ejemplo:
if (a_path.length >= 2
&& a_path[a_path.length-1] == 'mapThisProperty'
&& a_path[a_path.length-2] == 'insideThisProperty')
result = ko.observable(a_what);
Puedes usar tipo de a_qué en la condición, por ejemplo, para hacer observables todas las cadenas. Puede ignorar algunas propiedades e insertar otras nuevas en ciertos niveles. O incluso puede omitir un sendero. Etc
Las ventajas son:
- Personalizable (más fácilmente que knockout.mapping).
- Lo suficientemente corto como para copiarlo y pegarlo y escribir asignaciones individuales para diferentes objetos si es necesario.
- código más pequeño, knockout.mapping-latest.js no está incluido en su página.
- Debería ser más rápido ya que solo hace lo que es absolutamente necesario.
Respondido el 16 de enero de 15 a las 10:01
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas performance knockout.js knockout-mapping-plugin or haz tu propia pregunta.
Necesitaré algo de tiempo para ver si realmente mejora el rendimiento. ¿Podría dar un código de muestra para describir cómo puedo usarlo en mi caso en particular? - tusharmath