gratis - habilitar javascript en chrome en windows
Cómo detener el intenso bucle de Javascript al congelar el navegador (10)
Estoy usando Javascript para analizar un archivo XML con aproximadamente 3.500 elementos. Estoy usando una función jQuery "each", pero podría usar cualquier forma de loop.
El problema es que el navegador se congela durante unos segundos mientras se ejecuta el ciclo. ¿Cuál es la mejor manera de detener la congelación del navegador sin ralentizar demasiado el código?
$(xmlDoc).find("Object").each(function() {
//Processing here
});
Como una modificación de @ tj111 responda el código completo utilizable
//add pop and shift functions to jQuery library. put in somewhere in your code.
//pop function is now used here but you can use it in other parts of your code.
(function( $ ) {
$.fn.pop = function() {
var top = this.get(-1);
this.splice(this.length-1,1);
return top;
};
$.fn.shift = function() {
var bottom = this.get(0);
this.splice(0,1);
return bottom;
};
})( jQuery );
//the core of the code:
var $div = $(''body'').find(''div'');//.each();
var s= $div.length;
var mIndex = 0;
var process = function() {
var $div = $div.first();
//here your own code.
//progress bar:
mIndex++;
// e.g.: progressBar(mIndex/s*100.,$pb0);
//start new iteration.
$div.shift();
if($div.size()>0){
setTimeout(process, 5);
} else {
//when calculations are finished.
console.log(''finished'');
}
}
process();
Consideraría convertir los 3500 elementos de xml a JSON en el servidor o incluso mejor subirlo al servidor convertido, para que sea nativo de JS desde el getgo.
Esto minimizaría su carga y, por ende, también reduciría el tamaño del archivo.
Establezca un intervalo de tiempo entre el procesamiento para evitar que el ciclo de ciclo consuma todos los recursos del navegador. En total, solo tomará unos segundos procesar y recorrer todo, no es descabellado para 3.500 elementos.
var xmlElements = $(xmlDoc).find(''Object'');
var processing = function() {
var element = xmlElements.shift();
//process element;
if (xmlElements.length > 0) {
setTimeout(processing, 5);
}
}
processing();
Javascript tiene un único subproceso, por lo que, aparte de setTimeout
, no hay mucho que pueda hacer. Si el uso de Google Gears es una opción para su sitio, ofrecen la capacidad de ejecutar javascript en un hilo de fondo real.
Los bucles largos sin congelar el navegador son posibles con el marco Turboid. Con él, puedes escribir código como:
loop(function(){
// Do something...
}, number_of_iterations, number_of_milliseconds);
Más detalles en este artículo de turboid.net: Loops reales en Javascript
Me gustaría deshacerme de la función "cada" a favor de un bucle for ya que es más rápido. También agregaría algunas esperas usando el "setTimeout" pero solo de vez en cuando y solo si es necesario. No desea esperar 5 ms cada vez porque luego procesar 3500 registros tomaría aproximadamente 17,5 segundos.
A continuación se muestra un ejemplo que utiliza un ciclo for que procesa 100 registros (puede ajustarlo) a intervalos de 5 ms, lo que da una sobrecarga de 175 ms.
var xmlElements = $(xmlDoc).find(''Object'');
var length = xmlElements.length;
var index = 0;
var process = function() {
for (; index < length; index++) {
var toProcess = xmlElements[index];
// Perform xml processing
if (index + 1 < length && index % 100 == 0) {
setTimeout(process, 5);
}
}
};
process();
También compararía las diferentes partes del procesamiento xml para ver si hay un cuello de botella en algún lugar que pueda ser reparado. Puede comparar en Firefox usando el generador de perfiles de firebug y escribiendo a la consola de esta manera:
// start benchmark
var t = new Date();
// some xml processing
console.log("Time to process: " + new Date() - t + "ms");
Espero que esto ayude.
Podría intentar acortar el código por
$(xmlDoc).find("Object").each(function(arg1) {
(function(arg1_received) {
setTimeout(function(arg1_received_reached) {
//your stuff with the arg1_received_reached goes here
}(arg1_received), 0)
})(arg1)
}(this));
Esto no te hará mucho daño;)
Puede utilizar la API para trabajadores de HTML5, pero eso solo funcionará en Firefox 3.1 y Safari 4 betas atm.
Tuve el mismo problema que estaba sucediendo cuando el usuario refrescó la página sucesivamente. El motivo fueron dos bucles anidados que ocurrieron más de 52 000 veces. Este problema era más severo en Firefox 24 que en Chrome 29 ya que Firefox se bloqueaba antes (alrededor de 2000 ms antes que Chrome). Lo que simplemente hice y funcionó fue que utilicé bucles "for" en lugar de cada uno y luego refactoreé el código para dividir todo el conjunto de bucles en 4 llamadas separadas y luego fusionar el resultado en uno. Esta solución ha demostrado que ha funcionado.
Algo como esto:
var entittiesToLoop = ["..."]; // Mainly a big array
loopForSubset(0, firstInterval);
loopForSubset(firstInterval, secondInterval);
...
var loopForSubset = function (startIndex, endIndex) {
for (var i=startIndex; i < endIndex; i++) {
//Do your stuff as usual here
}
}
La otra solución que también funcionó para mí fue la misma solución implementada con Worker APIs
de HTML5. Use el mismo concepto en los trabajadores ya que evitan que su navegador se congele porque se ejecutan en el fondo de su hilo principal. Si solo aplicar esto con la API de Trabajadores no funcionó, coloque cada una de las instancias de loopForSubset
en diferentes trabajadores y loopForSubset
el resultado dentro de la persona que llama principal de Worker.
Quiero decir que esto podría no ser perfecto, pero esto funcionó. Puedo ayudar con fragmentos de código más reales, si alguien todavía piensa que esto podría encajarlos.
puede establecer TimeTime () con una duración de cero y se producirá según lo deseado