Seleccionar página
benchmarkEn muchas ocasiones vamos a necesitar obtener el tiempo en el que se ejecuta una porción de código a fin de realizar algún tipo de análisis de rendimiento y optimización. Esta es una técnica básica, pero existen varias formas de abordar esta medición, con sus ventajas e inconvenientes.

Vamos a revisar a continuación algunas de ellas y veremos cómo se ajustan a las diferentes necesidades y situaciones que nos podemos encontrar a fin de seleccionar la que mejor se adapta a nuestro caso.

Actualización: si quieres ver algunas alternativas modernas a las técnicas aquí presentadas, puedes consultar Tiempo de alta precisión en Javascript.

Date.now()

Es método más habitual de medir el tiempo que se dedica a una porción de nuestro código es obtener la hora antes y después de su ejecución y calcular el tiempo que se ha consumido:

var start = Date.now();

// Lo que queremos medir
var a = new Array(10000000);
for (var n = 0; n < a.length; n++) {
    a[n] = n * n;
}
var end = Date.now();

console.log(end - start);

Sólo hay que tener en cuenta que Date.now() está disponible en navegadores algo modernos. Si queremos utilizar esta técnica con navegadores muy antiguos, debemos utilizar una función de este tipo para que funcione correctamente:

if (!Date.now) {
    Date.now = function now() {
        return new Date().getTime();
    };
}

El mayor inconveniente que tiene este método es que creamos nuevas variables dentro de nuestro programa, lo cual puede llegar a ser molesto y fuente de alguna confusión o error. No obstante, es un método sencillo y rápido que se utiliza muy a menudo.

Actualización: Consulta las diferencias entre Date.now() y el nuevo API performance.now() y comprueba como mejora la precisión a la hora de medir la ejecución de código.

console.time() y console.timeEnd()

Si utilizamos versiones modernas de los navegadores o Node.js, podemos hacer uso de una funcionalidad no estándar, pero muy útil que ofrece el objeto console. La ventaja de este método es que no creamos nuevas variables que puedan afectar a nuestro programa. Para ello simplemente tenemos que llamar a console.time(), pasando como parámetro un texto identificador, antes de la ejecución que queremos medir y llamar a console.timeEnd() con ese texto identificador al terminar la ejecución.

console.time('loop');

// Lo que queremos medir
var a = new Array(10000000);
for (var n = 0; n < a.length; n++) {
    a[n] = n * n;
}

console.timeEnd('loop'); // Muestra por consola: "loop: 63ms"

Una ventaja añadida del uso de console.time() y console.timeEnd() es que podemos tener varios timers simultáneamente, sólo tenemos que utilizar textos identificadores diferentes.

microprofiler

Es posible que estas técnicas de medición se nos queden un poco cortas en algunos casos, especialmente con Node.js, ya que tenemos que realizar la medición en un contexto más preciso o donde es conveniente medir la ejecución del código tras varias ejecuciones. Para solucionar este problema está el paquete microprofiler (npm, github) de Alex Fernández.

Este módulo permite hacer una medición muy precisa de una parte de nuestro código llamando a los métodos start() y measureFrom() antes y después del código que queremos medir.

var microprofiler = require('microprofiler');
var start = microprofiler.start();

// Lo que queremos medir
var a = new Array(10000000);
for (var n = 0; n < a.length; n++) {
    a[n] = n * n;
}

var elapsedUs = microprofiler.measureFrom(start);
console.log(elapsedUs);

Este módulo devuelve los datos en microsegundos, no en milisegundos como en los casos anteriores, lo cual es de gran utilidad si estamos haciendo microptimizaciones. Además de mayor precisión, este módulo tiene funcionalidades muy interesantes como poder medir el tiempo de ejecución cada n veces. De esta forma es posible incluir esta medición en procesos que se repiten de forma continuada en la ejecución y obtener datos sucesivos.

Profilers

No podemos terminar sin hacer una meción a las herramientas de profile que disponemos en navegadores o Node.js y que permiten capturar el tiempo de ejecución del código y mostrarlo de forma más o menos descriptiva. Esta aproximación mide todo el código en forma de arbol, es decir, se descompone el tiempo de ejecución en cada función llamada, y es muy diferente a la que hemos planteado aquí, ya que en los casos anteriores estamos midiendo una porción de código y con los profilers estamos midiendo todas las funciones.

Novedades

Limitar el tamaño de un Map

Limitar el tamaño de un objeto Map no parece una idea muy razonable, pero cuando tu programa se ejecuta sin interrupción durante días, semanas, meses e inclusos años, es muy importante controlar el tamaño de la memoria utilizada para evitar problemas inesperados. Una simple función memoize puede llegar a almacenar mucha más información de la que puedes pensar. Aquí te contamos como limitar el tamaño de un objeto Map para estas situaciones.

Cómo conseguir un objeto Map ordenado

Mantener un objeto Map con su contenido ordenado no es algo tan sencillo como parece. Por defecto, Map guarda los datos en el mismo orden en el que han sido creados en el objeto. Para conseguir que el contenido se muestre ordenado tendremos que explorar varias interesantes alternativas que nos descubrirán algunas de características interesantes de estas estructuras de datos.

¿Es una función nativa de Javascript?

Comprobar si una determinada función es una función nativa de Javascript o es una función escrita en código es algo más complicado de lo que pueda parecer a primera vista. No hay grandes diferencias entre una función nativa y una escrita por nosotros, por lo que tenemos que buscar mecanismos algo indirectos para poder diferenciarlas.