Depuración de procesos JavaScript

Velneo incorpora un depurador de procesos javascript que nos permitirá encontrar y solucionar incidencias en nuestros desarrollos.

Podremos depurar en remoto cualquier aplicación instalada en un Velneo vServer, sin importar la ubicación. El depurador de procesos JavaScript se invoca desde Velneo vDevelop. Eso quiere decir que, si queremos depurar un proceso JavaScript de una instancia concreta de un servidor concreto, éste debe disponer al menos de un puesto de edición. Nos conectarnos con Velneo vDevelop a ese servidor y cargaremos la solución.

Para depurar un proceso o un manejador de evento JavaScript hemos de incluir un punto de interrupción en el mismo. Un punto de interrupción hace que, cuando ejecutemos el proceso JavaScript en modo de depuración, al lanzarlo se abra la ventana de depuración.

Para ejecutar la instancia en modo de depuración ejecutar la opción depurar solución actual (shift + F5) del menú soluciones.

En tiempo de ejecución, en el momento en el que se dispare el proceso, un manejador de evento o una excepción no controlada del script, se abrirá la ventana de depuración, en la cual podremos ir revisando el circuito que sigue nuestro código, comprobar variables, objetos en memoria, etc. que se vayan usando a lo largo del mismo.

La ejecución del proceso se detendrá en la primera instrucción que no sea un comentario.

En el código que se muestra en la ventana de depuración se incluye todo el relativo a los diferentes includes que se hayan usado en ese proceso o manejador de evento.

En cualquier caso, la evaluación del script también puede detenerse debido a alguna de las razones siguientes:

  • Se encontró una instrucción de depurador.

  • Se hace clic sobre un punto de interrupción.

  • Sucede una excepción no controlada en el script.

Información que podemos obtener en el depurador

Una vez que se lanza el depurador, se puede inspeccionar el estado de la depuración, por ejemplo, se puede consultar el valor de las variables, mostrar el stack (la pila de llamadas) de la línea en curso.

Así mismo, también se pueden añadir puntos de interrupción en las líneas que nos interese del script (mediante la opción conmutar punto de interrupción del menú depurar del depurador).

El depurador continuará la ejecución del script cuando se ejecuten las opciones indicadas al comienzo del capítulo El depurador será mostrado nuevamente si se da alguna de las condiciones que describimos a continuación:

Componentes del depurador

La funcionalidad del depurador está dividida en una serie de componentes, cada uno es un dock que se muestra en la ventana principal del depurador. A continuación pasamos a describir cada componente y su interrelación entre ellos.

Stack (pila)

Muestra una traza del estado de ejecución del script. Cada fila representa una trama en la pila. Una fila contiene el índice de marco (siendo 0 el marco más interno), el nombre de la función de script, y la ubicación ( nombre de archivo y número de línea ) . Para seleccionar un marco de pila especial para inspeccionar, hacer clic en su fila.

Variables locales

Muestra las variables locales de la línea seleccionada en la ventana de stack, esto es, las propiedades de los objetos en la cadena (scope) de su ámbito y el objeto “this”. Los objetos pueden expandirse, de modo que sus propiedades pueden ser examinadas, recursivamente.

Las propiedades cuyo valor haya cambiado se muestran en negrita.

Las propiedades que no sean de sólo lectura podrán ser editadas. Haciendo doble clic en el valor y tecleando el nuevo valor; el valor puede ser una expresión arbitraria. La expresión será evaluada en el ámbito del stack asociado. Tecleando, podemos presionar la tecla TAB para autocompletar la expresión.

En la imagen anterior vemos que en el script se usa una variable llamada x cuyo valor podemos inspeccionar en este panel.

Variables locales

En esta ventana se muestran las variables que en ese momento hay en la ejecución del script. De las variables se puede ver su valor.

Código

En esta ventana se muestra el código del script en curso. La ventana muestra una flecha en el margen izquierdo para señalar la línea del código que está siendo ejecutada. Haciendo clic en el margen de una línea podemos añadir un punto de interrupción en la misma. Un punto de interrupción tiene que establecerse en una línea que contenga una declaración real para que sea de utilidad. Cuando suceda una excepción no controlada, la línea que ha generado el error se mostrará con el fondo en rojo.

Esta ventana es de sólo lectura, no puede ser utilizada para editar y re-evaluar scripts. Sin embargo, esto es posible desde la consola. Más adelante explicaremos los comandos de consola.

Puntos de interrupción

En esta ventana se muestran todos los puntos de interrupción establecidos. Podemos habilitar o deshabilitar un punto de interrupción haciendo clic en el checkbox junto al ID del punto de interrupción (el ID se facilita para que el punto de interrupción pueda ser manipulado a través del dock de consola).

Se puede asociar una condición a un punto de interrupción; la condición puede ser una expresión arbitraria que devuelve verdadero o falso. El punto de interrupción solamente será disparado cuando se alcance su localización y la condición evaluada devuelva verdadero.

De modo similar, si al contador de ignorar puntos de interrupción se le asigna un valor N, el punto de interrupción será ignorado N veces en su ejecución.

En la captura de pantalla anterior se muestra cómo se ha insertado un punto de interrupción condicionado a que la variable x, usada como variable del bucle for, valga 3. En este caso, el depurador se parará en esta línea solamente cuando la variable x sea igual a 3.

Cada sesión del depurador JavaScript está encapsulada en una máquina virtual JavaScript, por este motivo los puntos de interrupción creados durante la depuración, no se guardan al finalizar la ejecución de cada script.

Salida de debug

Esta ventana muestra mensajes generados por la función de script print(). Los scripts pueden usar la variable especial __FILE__ para incluir la localización de la información actual en los mensajes.

En nuestro script podemos incluir una línea de instrucción como:

print(__FILE__)

En la captura de pantalla anterior vemos el resultado que va generando la función print() en cada iteración del bucle.

Log de errores

La ventana de log de errores muestra los mensajes de error que han sido generados. Todas las excepciones no controladas que sucedan en el motor de procesos.

En la captura de pantalla anterior se puede ver un error detectado por el depurador.

Expresiones

En esta ventana podemos añadir las expresiones que necesitamos evaluar. De esa manera, a medida que ejecutamos el código en el depurador, se visualiza el resultado de todas las expresiones.

Las expresiones añadidas se guardan para la siguiente ejecución, para cada instancia, facilitando el trabajo del desarrollador.

En la captura de pantalla anterior hemos creado la expresión registro.isOK() del script y nos devuelve el valor que ésta devuelve al ser ejecutada la línea correspondiente.

Consola

La ventana de consola provee una interfaz de línea de comandos para la funcionalidad del depurador, y también sirve como un intérprete interactivo de scripts. El conjunto de comandos y su sintaxis está basado en GDB, el depurador de GNU. Los comandos y las variables de script pueden ser autocompletados pulsando la tecla TAB.

Cualquier comando de consola que provoque un cambio en el debugger o en el estado de destino del depurador será reflejado inmediatamente en los otros componentes del depurador (por ejemplo, cambios en puntos de interrupción o en variables).

La consola provee una simple pero poderosa forma de manipular el entorno del script. Por ejemplo, tecleando “x” y pulsando intro, evaluará “x” en la ventana del stack y mostrará el resultado. Tecleando “x = 123” asignará el valor 123 a la variable x en el ámbito actual (o crear una variable global x si no existe — los scripts evaluados mediante consola tiene efectos colaterales arbitrarios, así que debemos tener cuidado).

Esta opción es para usuarios avanzados. Todos los comandos que contempla se pueden hacer de manera interactiva en el propio depurador.

En la captura de pantalla anterior hemos incluido la expresión registro.isOK() en la línea de comandos (QSDB) y al pulsar enter nos muestra el resultado de evaluar dicha expresión.

Continuar tras una excepción no controlada

Cuando sucede una excepción n controlada, no es posible continuar evaluando la función actual de modo normal. Sin embargo, podemos usar el retorno de la consola de comandos para atrapar la excepción y devolver un valor a la función de llamada.

Referencia de comandos de consola (para usuarios avanzados)

Se puede obtener escribiendo “.help” en la consola.

Comandos de puntos de interrupción

Establecer punto de interrupción

break

Establece un punto de interrupción en una línea de código determinada.

.break foo.qs:123

Este comando establece un punto de interrupción en la línea línea 123 de foo.qs.

.break 123

Este comando establece un punto de interrupción en la línea 123 del script en curso; el script en curso es el script asociado al marco de la pila actual.

Cada punto de interrupción tiene un identificador único (un número) asociado al mismo. Este identificador es requerido por otros comandos relativos a los puntos de interrupción.

clear

.clear foo.qs:123

Borra el punto de interrupción de la línea 123 del fichero foo.qs.

clear 123

Borra el punto de interrupción en la línea 123 de script en curso; el script en curso es el script asociado al marco de la pila actual.

.condition

Establece una condición a un punto de interrupción.

.condition 1 i > 42

Indica que el punto de interrupción 1 solamente será disparado si la variable i es mayor que 42.

La expresión puede ser una expresión arbitraria, pero puede tener efectos inesperados. Puede ser cualquier expresión condicional válida de QScript.

delete

Elimina un punto de interrupción, por ejemplo, lo quita de la sesión de depuración actual.

disable

Inhabilita un punto de interrupción. El punto de interrupción seguirá existiendo, pero no parará la ejecución del programa.

enable

Habilita un punto de interrupción. Los puntos de interrupción están habilitados por defecto, así que solamente se necesitará usar este comando si se ha inhabilitado un punto de interrupción previamente.

ignore

Establece un nº de iteraciones en las que se ignorará el punto de interrupción, por ejemplo, el punto de interrupción no parará la ejecución del programa salvo que se haya alcanzado el número de iteraciones establecido. Esto puede, por ejemplo, ser útil en bucles para parar en una iteración específica.

.ignore 1 5

Especifica que el punto de interrupción será ignorado las siguientes 5 próximas iteraciones.

info breakpoints

Lista todos los puntos de interrupción que se han establecido.

.info breakpoints

tbreak

Establece un punto de interrupción temporal. El comando es idéntico al comando break, salvo que el punto de interrupción será borrado automáticamente tras haber sido alcanzado.

Comandos de ejecución

continue

Continúa la normal ejecución del script.

eval

Evalúa un programa.

finish

Continúa la ejecución hasta que la función actual termine y se alcance la siguiente instrucción (por ejemplo, la instrucción siguiente a la llamada a una función).

interrupt

Solicita la interrupción de la ejecución. La interrupción sucederá tan pronto como se alcance una nueva línea del script.

next

Continúa la ejecución hasta que se alcance una nueva instrucción; pero si la instrucción en curso es una llamada a una función, la llamada a la función será tratada como una única instrucción. Esto se hará en tiempos de conteo antes de que se detenga la ejecución; 1 es el valor por defecto.

return

Hace que el marco en curso vuelva a su llamador. Si se da alguna expresión, será enviada como resultado de la función (por ejemplo, reemplazando los valores de retorno de funciones). La expresión podrá ser cualquier expresión QScript válida.

step

Continúa la ejecución hasta que se alcanza una nueva instrucción. Si el número de iteraciones se da como argumento, esto se hará tantas veces antes de que la ejecución finalice. Como opuesto a next , step entrará en funciones cuando encuentre llamadas a funciones.

Comandos de pila

backtrace

Muestra una traza inversa de la ejecución en curso. La traza listará el nombre de función y su posición en el script para cada marco de la pila.

down

Selecciona el marco de la pila anterior. La ejecución no retornará a este marco, pero se tendrá acceso a sus variables locales.

frame

Este comando mueve al marco de la pila dado en el índice. El índice del marco superior de la pila es 0. Los marcos previos son numerados de 1 en adelante (el marco más al fondo de la pila tendrá el número de índice mayor).

info locals

Lista las variables que están en el ámbito de aplicación del marco actual.

up

Selecciona el marco siguiente de la pila.

Ámbito de actuación

Se pueden depurar procesos y manejadores de eventos ejecutados desde vClient en primer plano.

Es posible depurar procesos que son llamados desde otros procesos o manejadores que se estén ejecutando en 1º plano.

En la depuración de manejadores de eventos javascript si hacemos uso de elementos que alteren el interfaz, estos pueden interferir por su propia naturaleza en el ámbito de actuación del depurador, anulando esta funcionalidad.

No es posible depurar procesos ejecutados desde vDataClient.

No es posible depurar procesos ejecutados en 2º o 3er plano.

No es posible depurar triggers de tablas en disco ni procesos ejecutados desde los triggers. Para estos casos recomendamos al programador que pase la tabla a memoria o copiar el código en un proceso y ejecutarlo desde un botón de un formulario o una acción, por ejemplo.

No es posible depurar eventos disparados con la señal de pre-inicialización del marco de la aplicación.

Si ejecutamos en debug un proceso de un proyecto que está protegido, el sistema solicitará que se introduzca la contraseña de edición del proyecto, si se introduce la contraseña válida, continuará la depuración, en caso contrario, se detendrá.

Última actualización