Introducción
Una función potente que hace único a JavaScript es su capacidad de trabajar de forma asíncrona a través de funciones de devolución de llamada. Asignar devoluciones de llamada asíncronas te permite escribir código controlado por eventos, pero también hace que el seguimiento de errores sea una experiencia de peluquería, ya que JavaScript no se ejecuta de forma lineal.
Afortunadamente, ahora en las Herramientas para desarrolladores de Chrome, puedes ver la pila de llamadas completa de las devoluciones de llamada asíncronas de JavaScript.
Una vez que habilites la función de pila de llamadas asíncronas en Herramientas para desarrolladores, podrás desglosar el estado de tu aplicación web en varios momentos. Recorre el seguimiento de pila completa de algunos objetos de escucha de eventos, setInterval
, setTimeout
, XMLHttpRequest
, promesas, requestAnimationFrame
, MutationObservers
y muchos más.
A medida que recorres el seguimiento de pila, también puedes analizar el valor de cualquier variable en ese punto particular de ejecución del tiempo de ejecución. Es como una máquina del tiempo para las expresiones del reloj.
Habilitemos esta función y veamos algunas de estas situaciones.
Cómo habilitar la depuración asíncrona en Chrome
Para probar esta nueva función, habilítala en Chrome. Ve al panel Fuentes de las Herramientas para desarrolladores de Chrome Canary.
Junto al panel Call Stack en el lado derecho, hay una nueva casilla de verificación para “Async”. Activa o desactiva la casilla de verificación para activar o desactivar la depuración asíncrona (aunque una vez que esté activada, es posible que no quieras desactivarla).
Capturar eventos de temporizador retrasados y respuestas XHR
Es probable que ya lo hayas visto en Gmail:
Si hay un problema para enviar la solicitud (ya sea que el servidor tenga problemas o haya problemas de conectividad de red en el lado del cliente), Gmail intentará volver a enviar el mensaje automáticamente después de un tiempo de espera breve.
Para ver cómo las pilas de llamadas asíncronas pueden ayudarnos a analizar eventos de temporizador retrasados y respuestas XHR, recreamos ese flujo con un ejemplo de Gmail de prueba. Puedes encontrar el código JavaScript completo en el vínculo anterior, pero el flujo es el siguiente:
Si solo observas el panel Call Stack en versiones anteriores de Herramientas para desarrolladores, una interrupción dentro de postOnFail()
te brindaba poca información sobre el origen desde el que se llamaba a postOnFail()
. Sin embargo, observa la diferencia cuando actives las pilas asíncronas:
Con las pilas de llamadas asíncronas activadas, puedes ver toda la pila de llamadas para ver con facilidad si la solicitud se inició desde submitHandler()
(lo que sucede después de hacer clic en el botón de envío) o desde retrySubmit()
(lo que sucede después de un retraso de setTimeout()
):
Observa expresiones de forma asíncrona
Cuando recorres toda la pila de llamadas, las expresiones observadas también se actualizan para reflejar el estado en el que se encontraban en ese momento.
Evalúa el código a partir de permisos anteriores
Además de simplemente observar expresiones, puedes interactuar con el código desde alcances anteriores en el panel de la consola de JavaScript de Herramientas para desarrolladores.
Imagina que eres el Dr. Who y necesitas ayuda para comparar el reloj de antes de llegar a Tardis con el “ahora”. Desde la consola de Herramientas para desarrolladores, puedes evaluar, almacenar y realizar cálculos fácilmente en valores desde diferentes puntos de ejecución.
Permanecer dentro de Herramientas para desarrolladores para manipular tus expresiones te ahorrará tiempo de tener que volver a tu código fuente, hacer modificaciones y actualizar el navegador.
Devela resoluciones de promesas encadenadas
Si creyeras que el flujo simulado de Gmail anterior era difícil de resolver sin la función de pila de llamadas asíncronas habilitada, ¿puedes imaginarte cuánto sería con los flujos asíncronos más complejos, como las promesas encadenadas? Repasemos el ejemplo final del instructivo de Jake Archibald sobre promesas de JavaScript.
A continuación, se muestra una pequeña animación del recorrido de las pilas de llamadas en el ejemplo async-best-example.html de Jake.
Obtén estadísticas sobre tus animaciones web
Profundicemos en los archivos de HTML5Rocks. ¿Recuerdas Leaner, Meaner, Faster Animations with requestAnimationFrame de Paul Lewis?
Abre la demostración de requestAnimationFrame y agrega un punto de interrupción al comienzo del método update() (cerca de la línea 874) de post.html. Con las pilas de llamadas asíncronas, obtenemos muchas más estadísticas sobre requestAnimationFrame, incluida la capacidad de caminar hasta la devolución de llamada del evento de desplazamiento iniciador.
Cómo hacer un seguimiento de las actualizaciones del DOM cuando se usa MutationObserver
MutationObserver
nos permite observar cambios en el DOM. En este ejemplo simple, cuando haces clic en el botón, se agrega un nuevo nodo del DOM a <div class="rows"></div>
.
Se agregó un punto de interrupción en nodeAdded()
(línea 31) en demo.html Con las pilas de llamadas asíncronas habilitadas, ahora puedes hacer que la pila de llamadas pase por addNode()
hasta el evento de clic inicial.
Sugerencias para depurar JavaScript en pilas de llamadas asíncronas
Nombra tus funciones
Si sueles asignar todas las devoluciones de llamada como funciones anónimas, tal vez quieras asignarles un nombre para facilitar la visualización de la pila de llamadas.
Por ejemplo, tomemos una función anónima como la siguiente:
window.addEventListener('load', function() {
// do something
});
Y dale un nombre como windowLoaded()
:
window.addEventListener('load', function <strong>windowLoaded</strong>(){
// do something
});
Cuando se activa el evento de carga, este aparecerá en el seguimiento de pila de Herramientas para desarrolladores con su nombre de función en lugar de la críptica "(función anónima)". Esto hace que sea mucho más fácil ver a simple vista lo que sucede en el seguimiento de pila.
Explora más
En resumen, estas son todas las devoluciones de llamada asíncronas en las que Herramientas para desarrolladores mostrará la pila de llamadas completa:
- Temporizadores: Vuelve a donde se inicializó
setTimeout()
osetInterval()
. - XHR: Vuelve a donde se llamó a
xhr.send()
. - Marcos de animación: Vuelve a donde se llamó a
requestAnimationFrame
. - Promesas: Regresa a donde se resolvió una promesa.
- Object.observe: regresa a la ubicación original de la devolución de llamada del observador.
- MutationObservers: Vuelve al lugar donde se activó el evento del observador de mutaciones.
- window.postMessage(): Revisar las llamadas de mensajería dentro del proceso.
- DataTransferItem.getAsString()
- API de FileSystem
- IndexedDB
- WebSQL
- Eventos del DOM aptos a través de
addEventListener()
: Vuelve a donde se activó el evento. Por motivos de rendimiento, no todos los eventos del DOM son aptos para la función de las pilas de llamadas asíncronas. Algunos ejemplos de eventos disponibles actualmente son "scroll", "hashchange" y "selectionchange". - Eventos multimedia a través de
addEventListener()
: Camina hasta donde se activó el evento. Entre los eventos multimedia disponibles, se incluyen los siguientes: eventos de audio y video (p.ej., "reproducir", "pausar", "cambiar la tarifa"), eventos de WebRTC MediaStreamTrackList (p.ej., "addtrack" y "removetrack") y eventos de MediaSource (p.ej., "sourceopen").
Poder ver el seguimiento de pila completa de tus devoluciones de llamada de JavaScript debería mantener esos pelos en la cabeza. Esta función de Herramientas para desarrolladores será especialmente útil cuando ocurren varios eventos asíncronos entre sí o si se arroja una excepción no detectada desde una devolución de llamada asíncrona.
Pruébalo en Chrome. Si tienes comentarios sobre esta nueva función, escríbenos en la herramienta de seguimiento de errores de las Herramientas para desarrolladores de Chrome o en el grupo de Herramientas para desarrolladores de Chrome.