Bjorn Tipling, publicó ayer un artículo con algunos consejos con los que mejorar el rendimiento de las aplicaciones javascript que interactuan con DOM, pero he estado haciendo pruebas de rendimiento y creo que es necesario comentarlas aqui para que veamos que es más optimo y que no lo és.
Escenario
El escenario en donde he realizado las pruebas es el siguiente:
- Windows XP
- Firefox 2.0.7
- Firebug 1.0.5
- Clase Timer en Javascript
1. No usar operaciones DOM para crear nodos.
Bjorn, comenta que la mejor opción para la creación de nodos es usar parentNode.innerHTML
, pero … los resultados son diferentes.
Código
var rep = 10000; //10.000
var parentNode = $('res');
var func = function() {
parentNode.innerHTML = "<div>Stuff</div>"
};
var func2 = function() {
var d = document.createElement("div");
d.nodeValue = "Stuff";
parentNode.childNodes[0] = d;
};
timer.start();
for (var x=0; x<rep; x++) func();
console.log("[NO_DOM]: " + timer.since());
timer.start();
for (var x=0; x<rep; x++) func2();
console.log("[DOM]: " + timer.since());
Resultados
[NO_DOM]: 2491
[DOM]: 705
2. Como excepción a la anterior, en los casos de insercción a continuación de lo que ya había, si que se recomienda usar DOM.
El comando parentNode.innerHTML +=
, consume una cantidad insana de tiempo, esto es una realidad y la prueba lo ha demostrado. He reducido el numero de repeticiones a 1.000 para evitar que se colgara el navegador.
Código
var rep = 1000; //1.000
var parentNode = $('res');
var func = function() {
parentNode.innerHTML += "<div>Stuff</div>"
};
var func2 = function() {
node = document.createElement("div");
node.innerHTML = "<div>More Stuff</div>";
parentNode.appendChild(node.childNodes[0]);
};
timer.start();
for (var x=0; x<rep; x++) func();
console.log("[NO_DOM]: " + timer.since());
timer.start();
for (var x=0; x<rep; x++) func2();
console.log("[DOM]: " + timer.since());
Resultados
[NO_DOM]: 40210
[DOM]: 344
3. No concatenes cadenas con +=
Bjorn publica unos ejemplos de como concatenar cadenas, pero las pruebas indican que los resultados no son muy diferentes.
Código
var rep = 10000; //10.000
var parentNode = $('res');
var func = function() {
html = "";
html += "<div>"
html += "Content"
html += "</div>"
parentNode.innerHTML = html;
};
var func2 = function() {
html2 = [];
html2.push("<div>")
html2.push("Content")
html2.push("</div>")
parentNode.innerHTML = html2.join("");
};
timer.start();
for (var x=0; x<rep; x++) func();
console.log("[NO_DOM]: " + timer.since());
timer.start();
for (var x=0; x<rep; x++) func2();
console.log("[DOM]: " + timer.since());
Resultados
[NO_DOM]: 2804
[DOM]: 2850
4. Dale un respiro a tu navegador despues de una buena tanda de insercciones DOM.
Parece obvio pensar que deberíamos darle un descanso a nuestro navegador despues de un intenso trabajo con DOM.
Código
var rep = 1000; //10.000
var parentNode = $('res');
function animation() {
console.log("Descanso");
};
var func = function() {
parentNode.innerHTML = "<div>Stuff</div>"
setTimeout(function(){animation();},0);
};
var func2 = function() {
var d = document.createElement("div");
d.nodeValue = "Stuff";
parentNode.childNodes[0] = d;
setTimeout(function(){animation();},0);
};
timer.start();
for (var x=0; x<rep; x++) func();
console.log("[NO_DOM]: " + timer.since());
timer.start();
for (var x=0; x<rep; x++) func2();
console.log("[DOM]: " + timer.since());
Resultados
[NO_DOM]: 485
[DOM]: 204
5. Ten cuidado con el tamaño de tu javascript.
El tamaño del nuestro javascript, no solo debe ser pequeño para evitar que la carga del usuario sea larga o pesada. Tambien hemos de pensar que el fichero es procesado por el navegador y a mayor tamaño, mayor procesamiento requiere.
6. Cargar javascript cuando lo necesitemos
Una solución para evitar que todo el javascript sea cargado al inicio, es la de segmentarlo e ir cargandolo cuando necesitemos.
7. Comprime tu javascript, 8. Gzip te ayuda
Evidentemente si comprimimos el JS, el tamaño del mismo será menor y por lo tanto ahorraremos tiempo de carga.
Código
var rep = 1000; //10.000
var parentNode = $('res');
var func = function() {
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
};
var func2 = function() {
eval(function(p,a,c,k,e,d){e=function(c){return c};if(!''.replace(/^/,String)){while(c--){d[c]=k[c]||c}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";2.1="0";',3,3,'HOLA|innerHTML|parentNode'.split('|'),0,{}))
};
timer.start();
for (var x=0; x<rep; x++) func();
console.log("[NO_DOM]: " + timer.since());
timer.start();
for (var x=0; x<rep; x++) func2();
console.log("[DOM]: " + timer.since());
Resultado
[NORMAL]: 4731
[COMPRESS]: 7347
En este ejemplo pretendo mostrar la diferencia de tiempo que tarda el PC en responder a la descompresión de código, en func2()
, tenemos la versión comprimida con Javascript Compressor (Packer de Dean Edwars) de func()
. Para complementar esta prueba, he realizado la prueba con la compresión plana, osea eliminando los carácteres especiales y en blanco, dejando una línea de texto.
Código
var rep = 1000; //10.000
var parentNode = $('res');
var func = function() {
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
parentNode.innerHTML = "HOLA";
};
var func2 = function() {
parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";parentNode.innerHTML="HOLA";
};
timer.start();
for (var x=0; x<rep; x++) func();
console.log("[NO_DOM]: " + timer.since());
timer.start();
for (var x=0; x<rep; x++) func2();
console.log("[DOM]: " + timer.since());
Resultados
[NORMAL]: 4782
[COMPRESS]: 4594
4 comentarios, 2 referencias
+
#