Consola de Firebug al detalle

24 Feb 2011

Prácticamente todos los programadores web que conozco, utilizan Firefox durante sus desarrollos y además, la gran mayoría, lo hace únicamente porque cuentan con la ayuda de Firebug. Y no es menos cierto que, con el tiempo, esta extensión se ha covertido en imprescindible gracias a las muchas utilidades que incorpora. De sus características, las que más destacan son sin duda la consola, el inspector DOM, el editor CSS y el perfilador Javascript.

En este artículo vamos a analizar la primera de ellas, la consola, exprimiendo al máximo sus posibilidades y convirtiéndola en la herramienta definitiva durante el desarrollo de aplicaciones Javascript.

La gran desconocida

Suelo decir que la consola de Firebug es una gran desconocida porque la mayoría de nosotros la utilizamos únicamente para mostrar mensajes de logs sin tener en cuenta el resto de sus posibilidades. Entre sus características, tenemos por ejemplo que puede agrupar mensajes mejorando su organización, mostrar objetos Javascript formateados y tabulados, monitorizar las trazas de un algoritmo, medir el tiempo que consume un script o incluso utilizarse como framework de pruebas al más puro estilo TDD o BDD.

Veamos cada una de estas características con más detalle…

Logging

La consola de Firebug es el mejor sustituto de los intrusivos alerts de toda la vida. Ya no es necesario detener la ejecución de un código congelando el navegador para ver el valor de un variable o para comprobar si nuestro script pasa por un determinado punto. En su lugar, podemos enviar mensajes personalizados con distintos estados a la consola que nos muestren valores en tiempo de ejecución a la vez que controlamos el flujo de la aplicación. Actualmente, existen cinco tipos de mensajes:

  • console.log(): es el método más simple y muestra un mensaje limpio sin más indicadores.
  • console.debug(): Escribe un mensaje en la consola incluyendo un enlace a la línea donde ha sido llamado.
  • console.info(): Escribe un mensaje en la consola acompañado de un icono ‘info‘ y un enlace a la llamada.
  • console.warn(): Escribe un mensaje en la consola acompañado de un icono ‘warn‘ y un enlace a la llamada.
  • console.error(): Escribe un mensaje en la pantalla acompañado de un icono ‘error‘ y un enlace a la llamada. Además lanza el evento Error

Un ejemplo de uso para cada uno de los tipos sería:

console.log( 'This is log message' );
console.debug( 'This is debug message' );
console.error( 'This is error message' );
console.info( 'This is info message' );
console.warn( 'This is warning message' );

El código anterior devuelve los siguientes resultados:

Patrones de sustitución

Como en la mayoría de lenguajes de programación, podemos utilizar un patrón de sustitución en nuestros mensajes para que sean reemplazados por valores dinámicos. Firebug utiliza para esta funcionalidad la misma especificación de C/C++.

Los reemplazos más usuales son los siguientes:

  • %s: String (cadena)
  • %d, %i: Integer (número entero)
  • %f: Float (número con coma flotante)
  • %o: Object (objeto)

NOTA: Actualmente, Firebug no soporta el formateado (truncado) de números enteros o flotantes.

La sintaxis es similar a la de otros lenguajes de la familia C:

var foo = 'Hello World';
console.log( 'A pattern message: %s', foo );

Sin embargo, una forma más sencilla de obtener el mismo resultado es mostrar el contenido de una variable u objeto añadiéndolo como argumento:

var obj = { foo : 'Hello World' };
var arr = [ "foo", "bar" ];
var str = "Hello";
 
console.log( 'The values are: ', obj, arr, str );

Esto nos da como resultado:

NOTA: Un truco práctico es limpiar la consola antes de mostrar nuestros resultados utilizando console.clear()

La consola permite mostrar a la vez el valor de tantos argumentos como necesitemos. Utilizando este método, Firebug parsea de forma interna los valores permitiendo ver su contenido de una forma legible, algo que no ocurre por ejemplo, si concatenamos mediante el símbolo de adición ‘+’:

var obj = { foo : 'Hello' };
var obj2 = { bar : 'World' };
 
console.log( 'Pretty Format: ', obj, obj2 );
console.log( 'Unlegible Format: ' + obj + obj2 );

Por lo tanto, cuando queramos concatenar variables, es mucho más interesante hacerlo mediante comas ‘,’ que mediante la adición tradicional de Javascript ‘+’.

Agrupando mensajes

Cuando estamos estableciendo puntos de control (o checkpoints) a lo largo de nuestro código, una opción interesante es agrupar los mensajes para evitar tener la consola llena de logs del tipo ‘Paso por aquí’, ‘Entrando en la función x’, etc…

var groupname = 'Group 1';
console.group( groupname );
console.log( 'Log message 1 from ', groupname );
console.log( 'Log message 2 from ', groupname );
console.log( 'Log message 3 from ', groupname );
console.groupEnd();
 
groupname = 'Group 2';
console.group( groupname );
console.log( 'Log message 1 from ', groupname );
console.log( 'Log message 2 from ', groupname );
console.log( 'Log message 3 from ', groupname );
console.groupEnd();

De esta forma creamos grupos desplegables con los que organizar cómodamente nuestros logs en la consola. Podemos incluso anidar grupos sin límites de niveles:

console.group( 'Group 1' );
  console.group( 'Group 2' );
    console.group( 'Group 3' );
      console.log( 'Hello World' );
    console.groupEnd();
  console.groupEnd();
console.groupEnd();

Formateando objetos

Para mostrar el contenido de nuestros objetos en un formato especial más apropiado, utilizamos console.dir() :

var obj = {
  'name' : 'Javascript, the Good Parts',
  'author' : 'Douglas Crockford',
  'date' : 'May 2008',
  'publisher' : 'Yahoo Press',
  'summary' : {
    'Chapter 1' : 'The Begining',
    'Chapter 2' : 'The Content'
  }
}
 
console.dir( obj );

Y obtendríamos:

El resultado es mucho más claro que el que obtendríamos con un console.log() , por lo que es buena práctica acostumbrarse a utilizar este método cuando pintamos objetos.

Formateando elementos HTML

En la misma línea del ejemplo anterior, podemos mostrar un árbol XML formateado con las etiquetas de un elemento HTML utilizando el método console.dirxml() :

var obj = jQuery('#access')[0]; // Collect DOM elements with jQuery
console.dirxml( obj );

El resultado sería todo el árbol correctamente fomateado:

Mostrando elementos tabulados

También es posible mostrar los datos en una tabla para aumentar la legibilidad. Para ello, es necesario que la fuente de datos se corresponda con un array de arrays o con una estructura similar (un array de objetos por ejemplo). Para ello, utilizamos el método console.table() .

Un ejemplo de esta funcionalidad:

var table1 = new Array(5);
for ( var i = 0; i < table1.length; i++){
  table1[ i ] = [ i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7 ];
}
 
console.groupCollapsed( "This is my table" );
console.table( table1 );
console.groupEnd();

Para recoger más los datos, he introducido el método groupCollapse para que nuestra tabla ocupe una fila desplegable:

El resultado quedá así recogido, limpio y legible. Realmente es un método poco utilizado ya que por lo general, no contamos con estructuras de este tipo, sin embargo es bueno conocerlo para cuando se dé la ocasión.

Las joyas de la consola: trazas, timings y asserts

Hasta ahora, hemos repasado las opciones más comunes de la consola, pero nos quedan aquellas menos conocidas que posiblemente encierran un mayor potencial.

Repasémoslas con sus correspondientes ejemplos.

Trazando nuestras aplicaciones

Durante la ejecución de una aplicación, es frecuente el ir saltando de una función a otra o recorrer una serie de métodos en una clase para obtener un determinado resultado. En este escenario, es interesante comprobar que tanto las llamadas que realizamos como los argumentos que pasamos sean los esperados.

Tomemos como ejemplo este código:

function launch( str ){
  return one( str );
}
function one( str ){
  //Do something...
  return two( str );
}
function two( str ){
  //Do something...
  return three( str );
}
function three( str ){
  return str;
}
 
console.log( launch( 'Hello World' ) );

Como podemos observar, es una aplicación completamente inútil que va saltando de una función a otra pasando siempre el mismo argumento para pintarlo por fin en el último paso. Imaginemos que este ejemplo es la estructura base de una programa mucho más complejo. Para monitorizar cada paso por una funcíon y ver el valor de los argumentos, podemos utilizar una de las joyas de firebug: console.trace() .

Incluyendo esta instrucción en el último paso de nuestro flujo, obtenemos toda el trazado que ha seguido hasta ahí incluyendo el valor de las variables involucradas.

Como es más difícil de explicar que ver, reescribamos la última función, three() , para utilizar esta funcionalidad:

function three( str ){
  console.trace();
  return str;
}

Con solo una llamada a console.trace() , obtenemos todo el flujo de ejecución hasta la función:

Sin duda, este método es de los más interesantes que ofrece la consola y una sólida herramienta para comprobar el flujo de nuestra aplicación y sus valores intermedios.

Midiendo el tiempo de ejecución de un script

Muchas veces, en Javascript tenemos la opción de escoger entre varios patrones para realizar una misma función. También puede darse el caso de que necesitamos optimizar al máximo el rendimiento de un determinado algoritmo. Para estos casos, contar con una herramienta que nos permita medir el tiempo transcurrido entre dos puntos de un programa, es fundamental para ayudarnos a elegir la mejor de las opciones posibles. Para ello, utilizamos el método console.time() .

Averigüemos por ejemplo qué método para recorrer un bucle es más rápido en Javascript: el patrón normal o el inverso.

// Normal Pattern
console.time('Checking Normal');
for( var x = 0; x < 1000000; x++){
    // Something interesting here...
};
console.timeEnd('Checking Normal');
 
// Inverse Pattern
console.time('Checking Inverse');
var i = 1000000;
while(i--){
    // Something interesting here...
}
console.timeEnd('Checking Inverse');

Como vemos, para medir los tiempos, rodeamos el código a testear entre los métodos console.time() y console.timeEnd() añadiendo un nombre que lo identifique.

El resultado es el siguiente:

Gracias al test, comprobamos que recorrer un bucle de forma inversa es sensiblemente más rápido que haciéndolo de forma incremental. ¡Es bueno tenerlo en cuenta!

Afirmaciones

Y llegamos a las afirmaciones. Pocos desarrolladores saben que Firebug puede utilizarse como un framework para pruebas al más puro estilo QUnit. Esto lo convierte en una herramienta útil para aplicar metodologías TDD, BDD o derivadas. Para ello, la consola acepta el método console.assert() que evalúa si una expresión es verdadera o falsa. En caso de no pasar el test, se envía un mensaje de error a la consola y se lanza una excepción. En su sintaxis más simple, tendríamos:

console.assert( 1 == 2, 'Testing Asserts' );

El segundo argumento, el nombre del test, es opcional. El resultado sería el siguiente:

Pero como resulta obvio, en una aplicación compleja, necesitamos un conjunto más amplio de afirmaciones para evaluar expresiones. En ese sentido, Firebug ofrece una interesante y amplia variedad de métodos:

  • console.assert(a, «message» [,objects]) – Afirma que a es verdadero.
  • console.assertEquals(a, b, «message» [,objects]) – Afirma que a es igual a b.
  • console.assertNotEquals(a, b, «message» [,objects]) – Afirma que a no es igual de b.
  • console.assertGreater(a, b, «message» [,objects]) – Afirma que a es mayor que b.
  • console.assertNotGreater(a, b, «message» [,objects]) – Afirma que a no es mayor que b.
  • console.assertLess(a, b, «message» [,objects]) – Afirma que a es menor que b.
  • console.assertNotLess(a, b, «message» [,objects]) – Afirma que a no es menor que b.
  • console.assertContains(a, b, «message» [,objects]) – Afirma que a está contenida en el array b.
  • console.assertNotContains(a, b, «message» [,objects]) – Afirma que a no está contenida en el array b.
  • console.assertTrue(a, «message» [,objects]) – Afirma que a es igual a True.
  • console.assertFalse(a, «message» [,objects]) – Afirma que a es igual a False.
  • console.assertNull(a, «message» [,objects]) – Afirma que a es igual a Null.
  • console.assertNotNull(a, «message» [,objects]) – Afirma que a no es igual a Null.
  • console.assertUndefined(a, «message» [,objects]) – Afirma que a es igual a Undefined.
  • console.assertNotUndefined(a, «message» [,objects]) – Afirma que a no es igual a Undefined.
  • console.assertInstanceOf(a, b, «message» [,objects]) – Afirma que a es una instancia del tipo b.
  • console.assertNotInstanceOf(a, b, «message» [,objects]) – Afirma que a no es una instancia del tipo b.
  • console.assertTypeOf(a, b, «message» [,objects]) – Afirma que el tipo de a es igual a la cadena b.
  • console.assertNotTypeOf(a, b, «message» [,objects]) – Afirma que el tipo de a no es igual a la cadena b.

ACTUALIZACIÓN IMPORTANTE:
Por alguna razón que desconozco, en las últimas versiones de Firebug (+1.7), se han eliminado todos los asserts anteriores dejándonos solo con el más simple de ellos. Es decir, que ahora no podemos realizar comparaciones más allá de si un valor es verdadero o falso. Aún así, mantengo la referencia por si vuelven a implementarlo en futuras versiones.

Funciones nativas

Además de todo lo anterior, Firebug ofrece una serie de funciones preconfiguradas que pueden resultar de utilidad cuando trabajamos directamente desde la línea de comandos:

  • $(«id») – Atajo de document.getElementById().
  • $$(«css») – Devuelve un array con los elementos que coinciden con un selector CSS.
  • $x(«xpath») – Devuelve un array con los elementos que coinciden con un selector XPath.
  • $0 – Variable que contiene el objeto inspeccionado más reciente.
  • $1 – Variable que contiene el siguiente elemento inspeccionado más reciente.
  • $n(5) – Devuelve el nth objeto inspeccionado más reciente.
  • inspect(object) – Muestra un determinado objeto en el inspector.
  • dir(object) – Devuelve un array con los nombres de las propiedades de un objeto dado.
  • clear() – Limpia la consola.

Y para los ‘console-ninjas‘, hay que recordar que el atajo de teclado Ctrl + Return permite ejecutar el código directamente desde la línea de comandos de la consola, evitando así pulsar con el ratón el botón ‘Ejecutar’.

Conclusión

En este artículo, hemos repasado algunas de las características más importantes de la consola de Firebug, demostrando que es una herramienta potente y flexible que nos permite mucho más que mostrar mensajes de tipo log.

Más:

{25} Comentarios.

  1. Alejandro

    Muy buen post, bastante contenido, tengo bastantes post sobre JS que leer en tu blog cuado tenga hueco 🙂

    Saludos

    • Carlos Benítez

      Gracias Alejandro; espero que te sean útiles.
      Saludos!

  2. Mikel

    Se acabó el utilizar la consola del firebug sólo para los errores y, sobre todo, se acabó el utilizar los alerts como método de logging (ups!).

    Gracias por el post.

  3. jdark

    Gran aporte, me había metido con «JavaScript debugger», pero me has hecho cambiar de opinión.

  4. aanton

    Un análisis muy completo! Acabo de descubrirlo y tengo muchos posts que leer! 🙂

    ¿Por cierto, este post está inspirado en este otro?
    http://www.thecssninja.com/javascript/console

    Saludos!

    • Carlos Benítez

      Hola; gracias por el Feedback.
      El artículo no está inspirado en el que comentas, de hecho, ambos fueron redactados el mismo día por ese tipo de coincidencias que tan a menudo se dan entre blogueros.

      Saludos!

  5. aanton

    He de decir que tu artículo me parece más completo y me gusta más!

    ¿Tienes pensado profundizar a corto plazo en otras características de firebug?

    Saludos!

    • Carlos Benítez

      En principio, el tema de la consola era el que me resulta más interesante y útil.

      Quizá prepare otro artículo sobre el JavaScript Profile y cómo monitorizar variables, crear puntos de ruptura, manejar la pila, etc…

      Saludos!

  6. Eduardo

    Buenas Carlos. Tienes algún artículo sobre espacios de nombre en javascript

  7. Raul

    Que buen post! He aprendido muchas cosas que no sabia sobre FireBug.

    Gracias y sigue asi, Carlos : )

  8. Jon Azpiroz

    Gracias Carlos, me has «descubierto» la consola. En el u-1 párrafo menionas el atajo Ctrl+Return, pero también basta con Return. ¿Interpreto bien?. Te sigo en Twitter
    Saludos

    • Carlos Benítez

      Hola Jon; el atajo Ctrl + Return es para cuando se abre la consola en modo multilínea. Ahí, el Return a secas solo nos permite el salto de línea, no lanzar la ejecución.

      Gracias por el feedback!

  9. sergio

    Felicidades por tu web, estoy devorandola.
    Respecto a console ¿no es un problema si te dejas codigo en produccion? Es decir, el objeto console solo esta disponible en firefox y ademas si tienes instalado firebug… Cuidado con no dejarte algo de este codigo en produccion y sufrir los errores silenciosos de javascript , no?

    • Carlos Benítez

      Si; efectivamente toda capa de tests en un software debería comentarse (no suprimirse) para su paso a producción.

      Otra solución interesante es comprobar si se dispone del objeto console en nuestro script para que, en caso negativo, podamos crear uno vacío de sustitución. Ben Alman nos lo explica en este post:

      JavaScript Debug: A simple wrapper for console.log

      Un saludo.

  10. Alexander Garzon

    Excelente artículo, Muy agradecido por su valioso contenido; todo muy bien explicado y documentado. Felicidades.

  11. Raul

    Excelente articulo y muy útil también para quienes tenemos una relación casi matrimonial con firebug. 🙂

  12. Micox

    Increíble.

  13. Cristian Rodriguez Cornejo

    Excelente material… podrías hacer un documento para poder imprimirlo de forma elegante.

    Saludos.

    • Carlos Benítez

      Es probable que complemente esta guía con más curiosidades y utilidades recientes de la consola de Firebug.
      Si reúno material suficiente, es probable que lo maquete como un PDF.

      Gracias por la idea,
      saludos!

  14. ivan

    Tengo un detalle con el console.log,

    Escribo en un for variables que van cambiando ya que leo un xml, pero no son escritas todas las posiciones, sino que hacen saltos, si le pongo adicionalmente un alert, es suficiente para que se vean, pero no es la idea, lo que veo que es un proceso asincrono, que escribe o no, que cambio para ver todas las posiciones.

    Si a los alert le doy aceptar mediante enter tambien pasa:
    x2009,2
    a)3
    x2009,3
    a)4
    x2009,4
    x2009,6
    a)7
    x2009,7

    No escribio
    a)5
    x2009,6
    a)6

  15. carlos

    Hola, muy bueno el blog. Alguien sabe cual es el atajo de teclado para ver un pagina web sin estilos, recuerdo que en versiones anteriores de firebug y firefox podria realizar esto, pero hace mucho que no lo uso y no logro podes ver las paginas de esta manera. Si alguien sabe se agradece. gracias!

    • Carlos Benítez

      Pues la verdad es que no conozco el atajo…

      Yo siempre he utilizado el plugin/extensión Web Developer para esto (https://addons.mozilla.org/es/firefox/addon/web-developer/). Ahí si tienes esa opción (que curiosamente sale en la misma captura que lo promociona).

      Si alguien sabe de otro método, estaría genial que lo compartiera.

      Saludos!

  16. Miguel

    Hola, Como puedo debugear, paso a paso, un script heredado, que creo en tiempo de ejecucion, ya que en firebug me aparece grisado, y aunque ponga el breakpoint, no para, por eso llegue a esta pagina la cual me ha servido de mucho, pero no encuentro en ninguna parte como hacer eso, ya que el script lo ejecuta en una ventana dialogo de jQueryUI y no lo muestra como los que se ejecutan al inicio, como digo sale es script grisado y el nombre es un numero. gracias.

  17. Laurence HR

    Cuando usaba firefox, también el firebug era uno de los complementos más importante como developer. Aunque actualmente uso chrome y su consola tiene todo esto implementado xD… Incluso ahora firebug tiene un bookmarklet que permite insertar su debugger en cualquier página sin necesidad de estar usando firefox x)

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *