Javascript Performance

La pagina de w3schools, es una referencia para todo tipo de desarrollo web. Da unos consejos para mejorar el rendimiento de código Javascript. Leyendo esa pagina he podido detectar unas “malas practicas” en contratos menores que podría dar un respiro a la pagina y reducir el tiempo de carga.

El consejo que mas me llamo la atencion es el siguiente:

Reduce DOM Access

Accessing the HTML DOM is very slow, compared to other JavaScript statements. If you expect to access a DOM element several times, access it once, and use it as a local variable:

Example:
var obj;
obj = document.getElementById("demo");
obj.innerHTML = "Hello";

En contratosmenores es una practica común seleccionar muchas veces todas las barras asi

svg.selectAll('svg .bar')

para hacerlas invisibles y luego volver a seleccionar las que corresponden a la acción de usuario para hacer visibles.

La primera selección es siempre la misma con lo cual podría hacer una sola vez al cargar la pagina y guardar en un objeto de javascript como aparece en el ejemplo de w3schools.

La manera de proceder para saber si ese cambio de verdad mejora el rendimiento, seria utilizar las herramientas de desarrolladores de Firefox o Chrome para hacer un benchmark para verificar cual es la mas performante.

EDIT 2017/06/15:

Antes de proceder con ese experimento, he encontrado mas información sobre la manera que d3.js hace las selecciones. En el blog de Mike Bostock https://bost.ocks.org/mike/selection/

commenta:

A Subclass of Array

You were probably told that selections are arrays of DOM elements. False. For one, selections are a subclass of array; this subclass provides methods to manipulate selected elements, such as setting attributes and styles. Selections inherit native array methods as well, such as array.forEach and array.map. However, you won’t often use native methods as D3 provides convenient alternatives, such as selection.each. (A few native methods are overridden to adapt their behavior to selections, namely selection.filter and selection.sort.)

Resumiendo, los métodos de d3.js extienden la clase Array, y según Mike no son arrays de DOM elements como los que resultarian de una selección nativa de javascript como la .getByClassName(). Son simples arrays que se convertirán en elementos de DOM a la hora de renderizar la pagina.

El benchmark.

Es difícil hacer un benchmark en un proyecto ya crecido como ese, sobre todo porque es difícil aislar lo que quieres evaluar. Finalmente he decidido aprovechar de la consola de javascript y sus métodos .time() y .timeEnd() para evaluar solo las dos maneras de seleccionar barras.

var barras = svg.selectAll('svg .bar');

console.time('benchmark'); svg.selectAll('svg .bar').style('visibility','visible');console.timeEnd('benchmark');

console.time('benchmark');barras.style('visibility','visible');console.timeEnd('benchmark');

He repetido diez veces el benchmark para sacar unas medias para las dos opciones que se pueden ver en la tabla:

 

Method/Selector selectAll(‘svg .bar’) var barras
.style(‘visibility’,’visible’) 8.42ms 3.37ms
.attr(‘class’,’foo’) 0.29ms 4.54ms

 

Evaluación

Lo que resulta interesante es que la dos maneras de seleccionar son buenas cada una para distintos métodos.

selectAll() resulta ultra rápido para asignar atributos a un elemento, pero tarda casi el doble en cambiar el estilo de un elemento comparando con la variable que tiene guardada la selecciones. Eso supongo que tiene que ver con como .selectAll() hereda los métodos nativos de Array.

Mi conclusión es que no mejoraría significativamente el redimiendo de la pagina optando por una u otra opción, y desde luego el principal problema es la primera carga de la pagina y no la parte donde se interactúa con el contenido.